我一直在阅读一些套接字指南,例如Beej的网络编程指南。现在很清楚,无法保证在单个recv()调用中接收了多少字节。因此,例如,应该发送前两个字节,说明消息长度,然后发送消息。因此,接收器接收前两个字节,然后在循环中接收,直到收到整个消息。一切都好又花花公子!?
一位同事问我有关消息不同步的消息。例如。如果,不知何故,我在一次recv()调用中收到两个字节,实际上是在消息本身的中间,它会显示为某个值的整数?这是否意味着发送的其余数据将不同步?那么部分地接收标题,即一次一个字节呢?
也许这是过度思考,但我无法在任何地方找到这一点,我只是想确定如果它可能对通信的完整性构成威胁,我会处理这个问题。
感谢。
答案 0 :(得分:1)
这不是过度思考。 TCP提供了一个流,所以你应该这样对待它。有关TCP的许多问题都是由网络问题引起的,并且在开发过程中可能不会发生。
启动一条带有(4字节)魔法的消息,您可以查找,然后按预期顺序(通常为大端)的(4字节)长度。当接收时,读取当时标头的每个字节,因此无论如何都可以处理接收到的字节。基于此,您可以接受持久TCP连接中的消息。
请注意,每条消息开始新连接时,您都知道起点。但是,如果仅过滤掉一些无效的消息,它也不会伤害发送魔法。
不需要校验和,因为TCP显示已经由TCP的接收部分检查的可靠字节流,并且只有在发送/接收存在编码问题时才需要同步。
另一方面,UDP发送数据包,因此您知道会发生什么,但是不能保证交付和订单。
答案 1 :(得分:1)
你的同事错了。 TCP数据不能无序到达。但是,您应该调查recv()
的MSG_WAITALL标志,以克服两个长度字节分别到达的可能性,并在接收消息体时消除对循环的需要。
答案 2 :(得分:0)
你有责任让你的客户端和服务器同步在一起,在TCP中如何没有乱序交付,如果你通过调用recv()得到了什么你可以认为你身后没有任何东西没收到。
所以问题是如何同步发送者和接收者?很容易,正如斯特凡凡夫所说,发送者和接收者都知道他们的出发点。这样您就可以为网络通信定义协议。例如,协议可以这样定义:
4个字节的标头,包括消息类型和有效负载长度
其余消息是有效负载长度
这样,你必须在发送实际有效载荷之前发送4字节的报头,然后发送实际的有效载荷。
由于TCP具有强大的Inorder可靠传输功能,因此您可以为每个包进行两次recv()调用。一个recv()调用,长度为4个字节,用于获取下一个有效负载大小,另一个调用recv(),其大小在头中指定。必须使recv()阻塞始终保持同步。
一个例子是这样的:
#define MAX_BUF_SIZE 1024 // something you know
char buf[MAX_BUF_SIZE];
int recvLen = recv(fd, buff, 4, MSG_PEEK);
if(recvLen==4){
recvLen = recv(fd, buff, 4);
if(recvLen != 4){
// fatal error
}
int payloadLen = extractPayloadLenFromHeader(buf);
recvLen = recv(fd, buff, payloadLen, MSG_PEEK);
if(recvLen == payloadLen){
recvLen = recv(fd, buff, payloadLen); // actual recv
if(recvLen != payloadLen){
// fatal error
}
// do something with received payload
}
}
正如您所看到的,我首先使用MSG_PEEK标志调用recv以确保是否有4个字节可用,然后接收实际标头。有效载荷相同