用clientsocket控件进行通讯,读取数据处理,当对方发送很快时,就发现多包数据赌在一起了,检验没通过,请教各位如何处理?

解决方案 »

  1.   

    参考下面贴子6楼的回复
    http://topic.csdn.net/u/20081114/11/091305bd-24cf-4c5c-9083-3993e4d98eae.html
      

  2.   

    可能是检验机制不太好,可以试试加头尾,和包长度,例如:
    #<长度><命令ID>[内容]*
    type
      PPacketHead = ^TPacketHead;
      TPacketHead = packed record
        Size: Word;
        CmdID: Byte;
      end;  PPacketData = ^TPacketData;
      TPacketData = packed record
        Packet: TPacketHead;
        Socket: TCustomWinSocket;
        PData: Pointer;
        PSize: Word;
      end;
    {实现部分}function IncPointer(PP: Pointer; Size: Integer = 1): Pointer; inline;
    var
      P: PAnsiChar;
    begin
      P := PAnsiChar(PP);
      Inc(P, Size);
      Result := P;
    end;function IsTail(PP: Pointer; Size: Word): Boolean; inline;
    var
      P: PAnsiChar;
    begin
      P := PAnsiChar(PP);
      Inc(P, Size);
      Result := P^ = '*';
    end;procedure OnRecvSocketEvent(Socket: TCustomWinSocket;
      PData: Pointer; Size: Integer);
    var
      PB, PH: PAnsiChar;
      P: PPacketHead;
      PD: TPacketData;
      K: Integer;
    begin
      inherited;
      K := 0;
      PB := PData;
      while K < Size do begin
        PH := StrPos(PB, '#'); //每个数据包是#开头*结尾
        if (PH <> nil) then begin
          if (K < Size) then begin
            P := IncPointer(PH);
            if (P^.Size > 0) and IsTail(PH, P^.Size + 1) then begin//处理这个包
               PD.Packet := P^;
              PD.Socket := Socket;
              PD.PData := IncPointer(P, SizeOf(TPacketHead));
              PD.PSize := P^.Size - SizeOf(TPacketHead);
              DoParse(PD);//自己按需要实现
              K := K + P^.Size + 2; //头尾长度=2
              PB := IncPointer(PB, K);
            end else
              PB := IncPointer(PB);
          end else
            PB := IncPointer(PB);
        end else Break;
      end;
    end;procedure OnRead(Sender: TObject; Socket: TCustomWinSocket);
    var
      Size: Integer;
      PData: Pointer;
    begin
      Size := Socket.ReceiveLength;
      if Size > 0 then try
        GetMem(PData, Size);
        Socket.ReceiveBuf(PData^, Size);
        OnRecvSocketEvent(Socket, PData, Size);
      finally
        FreeMem(PData);
      end;
    end;
      
    原理:先取包,然后校验包头尾和长度,合法就继续处理,不合法则不处理。
    这种方式不怕粘包,只怕断包,不过要判断断包也简单,方法如下:
    收到包后立即校验并将包分成一个一个的,存到临时数据里,如果最后一个包校验未通过,也就是说最后一个包如果是断包,则保存起来,
    下次收到的包放在这个断包后面一起校验就行了(可以用反向搜索字符串的方法快速找出最后一个包,并判断出是否是断包)。