recv有时不接收整个数据

mil*_*ilo 4 c++ linux network-programming recv

我有以下问题:这是代码块:

void get_all_buf(int sock, std::string & inStr) {
    int n = 1;
    char c;
    char temp[1024*1024]; 

    bzero(temp, sizeof(temp));

    n = recv(sock, temp, sizeof(temp), 0);

    inStr = temp;
};
Run Code Online (Sandbox Code Playgroud)

但有时recv返回不是整个数据(数据长度总是少于sizeof(temp)),只有它的一部分.写方面总是向我发送整个数据(我用嗅探器得到它).什么事?谢谢.

PS我知道,好的方式建议我检查n(if (n < 0) perror ("error while receiving data")),但现在没关系 - 这不是我的问题的原因.

PS2我忘记了 - 这是阻塞插座.

Ala*_*irG 11

TCP标准允许数据包的分段.实际上,对于几百字节左右的小数据包不会发生这种情况,但几兆字节的数据几乎肯定会被分割.

其次,当你说嗅探器说所有数据都发送到一个数据包或多个数据包?

良好的网络编程实践要求您不要假设消息以单个块的形式到达.两个连续的消息可以作为一个数据包到达(理论上但几乎从不在实践中),即使它们到达多个数据包也可以作为单个读取读取.一条消息可能会被分割成多个数据包,它们可能不会全部到达,这可能就是您所看到的.

您的程序应该缓冲其所有读取并具有一种机制来确定整个消息何时到达,或者通过分隔符(例如,用CRLFCRLF分隔的HTTP头)或者通过字节计数(例如,在其中指定长度的HTTP主体).标头)或通过关闭连接来指示数据的结束(例如,当标头中未指定内容长度时的HTTP主体).也可能有其他机制.

  • TCP与此无关.问题出在recv()函数中.由于信号等原因,recv可以返回所需的字节数. (2认同)

Jur*_*aho 6

更好的方法是使用以下:

void get_all_buf(int sock, std::string & output) {
    char buffer[1024];

    int n;
    while((errno = 0, (n = recv(sock, buffer, sizeof(buffer), 0))>0) || 
          errno == EINTR)
    {
        if(n>0)
            output.append(buffer, n);
    } 

    if(n < 0){
        /* handle error - for example throw an exception*/
    }
};
Run Code Online (Sandbox Code Playgroud)

另请注意,堆栈上分配的缓冲区要小得多.堆栈上有1M缓冲区可能导致堆栈溢出.

附加说明:您可能不希望在套接字关闭之前读取,因此您可能需要向while循环添加另一个终止条件.