如果客户端发送的一条消息数据是一定格式的,例如:消息头+消息内容长度+内容.客户端每隔一秒就发送一次.
实际中发现客户端发送消息到服务端,服务端每次接收的数据,有些是完整的,但有些只有消息头+消息内容长度+一半的内容,或者就只有一半的内容,也有些是接收的数据是几条消息并在一起的.有什么办法能让数据能让数据完整的接收呢,或是有什么办法在接收到这些残缺的消息后做处理可以让消息完整?另外,为何一次接收会有多条消息并在一起呢???

解决方案 »

  1.   

    因为TCP是流,所以你那里出现的现象都是正常的.一般是用4个字节表示长度后面跟包的内容,这样每个包都分清楚了,容易处理
      

  2.   

    残缺的包可以先暂存,下次收到以后在连接起来多个包处理可以这样:
    var
      Len: Integer;     //消息长度(或者是Word,或者是Byte,看自己怎么定义)
      S, sTemp: string; //收到的消息
      AHead: THead;     //自定义的消息头结构
    begin
      while Length(S) > (SizeOf(THead) + SizeOf(Integer)) do
      begin
        Move(S[1], AHead, SizeOf(THead)); //读取消息头
        Delete(S, 1, SizeOf(THead));      //删除消息头
        Move(S[1], Len, SizeOf(Integer)); //读取消息长度
        Delete(S, 1, SizeOf(Integer));    //删除消息长度
        sTemp := Copy(S, 1, Len);         //读取消息
        Delete(S, 1, Len);                //删除消息
      end;//while
      //其他处理
      if S <> '' then
      begin
        //这个是没有接收完的包...
      end;//if
      //...
      

  3.   

    如果你的消息长度包含了消息头和"消息长度"本身的长度的话,读出Len以后减去SizeOf(THead)和SizeOf(Integer)就可以了
      

  4.   

    TCP不会有残缺不全的数据的,一定是完整的消息数据,只是接收包的地方和你发送的是不一样的。
    发送的时候是一包一包发送的,接收不一定,可能一次接收了几个小的数据包,也可能几次接收一个大的数据包。
    可以这样解决:
    开辟一个缓冲区,每次接收数据后,都把数据追加到缓冲区中,缓冲区可以是一个队列的处理方式,然后判断缓冲区里是否有完整的数据包,通过自定义的结构来判断,消息头+消息内容长度+消息内容,有就处理,处理后把处理过的数据清掉,没有就继续等待接收。
      

  5.   

    沾包情况是包的大小一般超过1.3K或者路由上设置的MUT决定.如果小于这个值出现收到包不完整,那么基本可以断定是你的IOCP接收处理有问题.和发的格式无关.
      

  6.   

    IOCP不是阻塞的是针对一批连接来讲的,但对于一批里的某一个连接还是阻塞的方式,进行所以应该不会有数据乱的情况出现。如果楼主实在不放心可以,在发送程序里单独把包抽出来定义一个类来处理,然后在具体发送跟接收包时考虑以一个数组的方式来进发包跟组包的方式实现。
      

  7.   

    unsigned 的解释已经很完整了,也是最佳做法。既然消息数据的格式是固定的,如消息头+消息内容长度+内容,这里分别用 opcode datalen data 来表示在接收完 opcode 和 datalen 以后,传递给 WSARecv 的 buf 参数的 len 设置为 “消息内容长度”即可:WSABUF buf;
    buf.buf = recvbuff;
    buf.len = datalen;
    WSARecv(s, buf, 1, ...);也就是说告诉 WSARecv:这一次的接收最大只接受这么多数据,多出来的那部分数据就让它留在系统缓冲区中。另一方面,有时候 datalen 比较大,不能一次传输完成的情况下,就需要进行消息拼接,如:class CRecvBuff
    {
    public:
    char *m_lpBuff;
    int m_nBuffSize;
    WSABUF wsabuf;public:
         CRecvBuff(int nBuffSize)
         {
              m_lpBuff = new char[nBuffSize];
              m_nBuffSize = nBuffSize;
              wsabuf.buf = m_lpBuff;
              wsabuf.len = nBuffSize;
         }
    };void OnRecv(DWORD dwError, DWORD cbTransferred, CRecvBuff *buf)
    {
        // 递增缓冲区
        buff->wsabuf.buf += cbTransferred;    // 递减缓冲区长度
        buff->wsabuf.len -= cbTransferred;
        
        if (buff.len > 0)
        {
            // 此消息仍有数据未接收完,再次调用 WSARecv 接收剩下的数据
             WSARecv(s, &buf->wsabuf, 1, ...);
        }
        else
        {
            // 消息数据已经完成接收
             OnPacketRecvd(...);
        }
    }