首页 文章

Berkeley Socket:recv系统调用

提问于
浏览
0
//server side
void* s2(void *arg){
    info *s = (info*)arg;
    char buffer[MAXS];
    int k;
    sockaddr_in addr;
    socklen_t aSize = sizeof(sockaddr_in);
    int sfd = accept(s->fd,(sockaddr*)&addr,(socklen_t*)&aSize);
    if(sfd<0){
        s->current--;
        pthread_exit(0);
    }
    while(1){
        k = recv(sfd,buffer,MAXS,0);
        cout<<buffer<<"\n";
        //1. k ==0 socket has been closed by client 
        //2. k==-1 error in recv 
        //3. recv quit
        if((k==-1)||(!strncmp(buffer,"quit",4))||(k==0))break; 
        sprintf(buffer,"%d\n",(int)strlen(buffer)); //Convert length to  string using sprintf()
        send(sfd,buffer,strlen(buffer),0); //send buffer to client 
    }
    close(sfd);
    if(s->limit==s->current)
    FD_SET(s->fd,&sfds);
    s->current--; //decreament the client number 
    pthread_exit(0);
}

//client side
1. send(sockfd,"sadhdag",8,0);
2. send(sockfd,"ss",3,0);

服务器recv sadhdag 在第一次调用recv .

在第二次调用recv服务器recv

ss
dag

服务器端:

函数s2由一个线程运行,参数传递,套接字信息连接被接受,send和recv被调用onn新接受的客户端 .

为什么会这样?或者如何避免这种情况?

2 回答

  • 3

    你忽略了 recv() 返回的计数 . 与注释中的建议相反,在 recv() 之前没有必要将缓冲区归零,但是之后只需要使用该缓冲区直到该计数 . 例如:

    printf("%s", buffer);
    

    是错的,而且

    printf("%.*s", count, buffer);
    

    是正确的 .

    NB

    if((k==-1)||(!strncmp(buffer,"quit",4))||(k==0))break;
    

    也不正确 . 它应该是

    if((k==-1)||(k==0)||(k >= 4 && !strncmp(buffer,"quit",4))) break;
    

    除非 k 为正数,否则查看缓冲区无效,除非其中包含四个字符,否则无法比较其中的四个字符 .

  • 1

    您忘记实际实现任何类型的协议或应用程序级逻辑 . 总结一下:

    k = recv(sfd,buffer,MAXS,0);
        cout<<buffer<<"\n";
    

    此代码建议您使用换行符终止消息:

    sprintf(buffer,"%d\n",(int)strlen(buffer)); //Convert length to  string using sprintf()
        send(sfd,buffer,strlen(buffer),0); //send buffer to client
    

    如果是这样,那么在另一端解析该代码的代码在哪里?你抛弃返回的长度,所以你甚至不知道要检查换行符的字符 .

    TCP是一种字节流协议,不保留应用程序级别的消息边界 . 如果要使用它来发送字符串或其他应用程序级别的消息,则必须指定并实现应用程序级协议 .

    您调用 recv 来获取原始TCP数据,然后输出它就像它是一个字符串 . 如果你想象它是通过魔法发生的 .

    如果您希望将换行终止的消息接收到C风格的字符串中,您当然可以这样做 . 但是你必须实际编写代码才能完成它 .

相关问题