在我的简单TCP客户端服务器应用程序中,服务器重复向客户端发送1 kB消息,客户端为每个数据包发送应答确认(只发送'ACK')。试想一下这个场景,比如客户端和服务器在无限循环中传递1 kB消息。
我每次都发送相同的消息,第一个字节(第一个字符)总是1.但是在同一台机器上长时间测试这个客户端和服务器应用程序时,我注意到一些收到的消息的第一个字符是接收缓冲区中的其他内容和recv
函数也返回1024(1 kB)。这种情况不常发生。
这就是我收到的方式。
char recvBuff[DEFAULT_BUFFER_SIZE];
int iResult = SOCKET_ERROR;
iResult = recv(curSocket, recvBuff, DEFAULT_BUFFER_SIZE, 0);
if (iResult == SOCKET_ERROR)
{
return iResult;
}
if (recvBuff[0] != 1)
{
//malformed receive
}
MessageHeader *q = (MessageHeader*)recvBuff;
message.header = *q; q++;
std::string temp((char*)q, message.header.fragmentSize);
message.message = temp;
实际上问题在于构造临时字符串。由于没有收到正确的片段大小,它会中断。我试图删除这些格式错误的数据。但问题是,在收到格式错误后,上次成功接收的片段ID与第一个成功接收的片段ID之间存在差距。知道为什么这些不正常的接收会发生吗?
答案 0 :(得分:1)
您假设在recv()
电话完成后您收到了完整的消息。如果这是一个TCP连接(而不是UDP),它是面向字节的,这意味着只要任何 recv()
将返回 >可用字节。
更明确地说,没有理由做
send (toServerSocket, someMessage, 1024, 0);
客户端的将导致
recv (fromClientSocket, myBuffer, 1024, 0);
接收1,024个字节。它也可以接收27个字节,其余的997来自未来的recv()
。
您的计划中发生的事情是,您获得了其中一个短回报,并且导致您的程序失去同步。与消息流。怎么解决?使用recv()
来阅读您知道长度的足够消息(或设置固定长度,尽管在许多情况下效率很低)。然后继续调用recv()
进入缓冲区,直到读取至少那么多字节为止。 请注意,您可能会读取比消息长度更多的字节 - 也就是说,您可能会读取属于下一个消息的某些字节,因此您需要保留这些字节在处理当前消息后在缓冲区中。