包含消息长度的两个字节头的部分recv()怎么样?

时间:2016-12-16 09:28:49

标签: c++ c sockets

我一直在阅读一些套接字指南,例如Beej的网络编程指南。现在很清楚,无法保证在单个recv()调用中接收了多少字节。因此,例如,应该发送前两个字节,说明消息长度,然后发送消息。因此,接收器接收前两个字节,然后在循环中接收,直到收到整个消息。一切都好又花花公子!?

一位同事问我有关消息不同步的消息。例如。如果,不知何故,我在一次recv()调用中收到两个字节,实际上是在消息本身的中间,它会显示为某个值的整数?这是否意味着发送的其余数据将不同步?那么部分地接收标题,即一次一个字节呢?

也许这是过度思考,但我无法在任何地方找到这一点,我只是想确定如果它可能对通信的完整性构成威胁,我会处理这个问题。

感谢。

3 个答案:

答案 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个字节可用,然后接收实际标头。有效载荷相同