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);

服务器 recvsadhdag首次调用 recv 。

在第二次调用 recv 服务器 recv

ss
dag

服务器端:

函数 s2 由一个线程运行,参数通过套接字信息传递,在那里接受连接,并在新接受的客户端上调用 send 和 recv。

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

4

2 回答 2

3

你忽略了返回的计数recv()。与评论中的建议相反,之前没有必要memset()将缓冲区归零recv(),但之后需要使用该缓冲区直到该 count。例如:

printf("%s", buffer);

是错误的,并且

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

是正确的。

注意

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

也不正确。它应该是

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

除非是肯定的,否则查看缓冲区k是无效的,除非其中四个字符,否则比较其中的四个字符是无效的。

于 2015-02-26T04:21:35.567 回答
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 数据,然后将其作为字符串输出。如果你要定义和实现一个协议来通过 TCP 发送和接收字符串,你必须实际去做。你不能想象它是通过魔法发生的。

如果您想将换行符终止的消息接收到 C 风格的字符串中,您当然可以这样做。但是您必须实际编写代码才能做到这一点。

于 2015-02-26T04:38:33.327 回答