我用delphi的clientsocket.recievebuf 取数据的时候发现serversocket.socket.sendbuf 发出来的数据和客户端接收的数据量不等。
我在server端一共发送了9708个字节。但是接收端一共接收到两次,显示出信息如下:
recieve len:=8192
recieve len:=2408
总共接收到了 10600个字节。
尝试了很多次,都是这样子。百思不得不得其解。
请相关高手不吝赐教!

解决方案 »

  1.   

    该接收多少就接收多少,用SocketAPI写,非常好
      

  2.   

    一个TCP连接的两站,不管你发送端怎么发,每次多少字节,发多少次,
    接收方的接收只管在一个数据流中读,同发送端动作无关。因此,需要自己在这个SOCKET数据流里面用一定办法来同步两端动作。
    比如HTTP是发串数据,使用的是两个回车换行同步。
    RPC是发块数据,在块指定字段定义了块长度。。
      

  3.   

    我使用过了很多种方法,
    第一种 将 9708个字节以1024个字节为一个包发送。
    第二种 将9708个字节全部以一个包的形式发送。
    第三种 调用winsocket2 API 中的TransmitFile函数一下子将文件发送出去。
    第四种 调用底层API重新改写第一种、第二种两种方式。
    最后测试的结果类似。
    所有的错误都是在8192个字节后多了很多字节。现在是传9708个字节。我尝试了一下,传送大一点的数据,错误可能更多。
     
      

  4.   

    说清楚你具体的做法吧.最好贴出源码.不管直接使用SOCKET API还是组件本质都是一样的.发送的时候,SENDBUF会访回实际发出的字节数.至于接收,使用TClientSocket你的具体做法是什么?
    你好象是用的非阻塞方式,
     如果是阻塞方式,接收数据最好用TWinSocketStream.
      

  5.   

    clientsocket.onread事件
    var
       len:integer;
       buf:pbyte;
       bufcheck:pbyte;
    begin
         len:=Self.Socket.ReceiveLength;
         memo1.lines.add('recieved'+inttostr(len));
         buf:=GetMemory(len);
         bufcheck:=GetMemory(14);
         ZeroMemory(bufcheck,14);
         ZeroMemory(buf,len);
         self.Socket.ReceiveBuf(buf^,len);
         CopyMemory(bufcheck,ptr(integer(@(buf^))+(len-13)),13);
         if pchar(bufcheck)='SendFError_FT' then
         begin
              Freemem(buf);
              FreeMem(bufcheck);
              Self.Close;
              Self.Open;
              exit;
         end;
         if pchar(bufcheck)='SendFinish_FT' then
         begin
              memstream.Write(buf^,len-13);
              memo1.lines.add('alllength=',inttostr(memstream.size));
              FreeMem(buf);
              FreeMem(bufcheck);
              self.Close;
              Self.Destroy;
              Exit;
         end;
         memstream.Write(buf^,len);
         FreeMem(buf);
         FreeMem(bufcheck);其中memstream为全局 Tmemorystream
      

  6.   

    //问题是出在这儿:
    //在帮助上面也提到过,用Receivelength并不能精确取得实际读到的数据长度。
       len:=Socket.ReceiveLength;
       
    //应该判断这儿函数的返回值,才是真正有效读到的。
       len:=Socket.ReceiveBuf(buf^,len);
      

  7.   

    buf 你可以设固定长度,在一个WHILE循环中ReceiveBuf,直到没有数据读出。
      

  8.   

    我在什么地方进行这个循环。(在一个WHILE循环中ReceiveBuf,直到没有数据读出。)
      

  9.   

    大致做法是这样的...细节你自己想吧.procedure TForm1.ClientSocket1Read(Sender: TObject;
      Socket: TCustomWinSocket);
    var
      sBuf:string;  //用STRING只是因为我熟悉它.
      iSize:integer;
      fo:TMemoryStream;
    begin  fo:=TMemoryStream.Create;
      SetLength(sBuf,2000);  iSize:=Socket.ReceiveBuf(pchar(sBuf)^,2000);
      while iSize>0 do
      begin
        fo.Write(pchar(sBuf)^,iSize)
      end;
      .....
    end;
      

  10.   

    呵,没仔细看,确实写错了。。  iSize:=Socket.ReceiveBuf(pchar(sBuf)^,2000);
      if(iSize>0) fo.Write(pchar(sBuf)^,iSize)
      while (iSize=2000) do
      begin
        iSize:=Socket.ReceiveBuf(pchar(sBuf)^,2000);
        if(iSize>0) fo.Write(pchar(sBuf)^,iSize)
      end;
      

  11.   

    以上方法依然不通,问题是你还没了解winsocket的线程机制。如果再触发一次onread而
    while还没有循环完,那岂不是乱了。我试过了,不行。不过谢谢你。
      

  12.   

    什么winsocket的线程机制,在同步处理的时候才要考虑多线程.
    在异步非阻塞WINSOCKET中,这些事件统统都是在 主 线 程 触 发 的,
    这一点一定要清楚.
    也许上面具体程序没有调试过,并不等于解决不了问题.
      

  13.   

    其实不该说多了,
    你的关键问题就在使用了len:=Self.Socket.ReceiveLength;
      

  14.   

    另一方面,确定你发送端确实发了多少字节.贴出一个我才写的,调试了一下的.
    //--------------------------------------------------------
    type
      TForm1 = class(TForm)
        ClientSocket1: TClientSocket;
        Memo1: TMemo;
        Button1: TButton;
        Button2: TButton;
        procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
        procedure Button1Click(Sender: TObject);
        procedure ClientSocket1Connect(Sender: TObject;
          Socket: TCustomWinSocket);
        procedure ClientSocket1Disconnect(Sender: TObject;
          Socket: TCustomWinSocket);
        procedure Button2Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
        FStr:String;
        Fo:TStream;
        procedure DisplayMsg(s:string);
      end;var
      Form1: TForm1;implementation{$R *.dfm}procedure TForm1.ClientSocket1Read(Sender: TObject;
      Socket: TCustomWinSocket);
    var
      s:string;
      iSize:Integer;
    begin
      FSTr:='';
      SetLength(s,3);//这是故意设置这么短的,有问题则更容易暴露
      repeat
        iSize:=Socket.ReceiveBuf(pchar(s)^,3);
        if iSize>0 then
        begin
          SetLength(s,iSize);
          Fo.Write(pchar(s)^,iSize);
          FStr:=FSTr+s;
        end
      until (iSize<>3) or (iSize=-1);
      DisplayMsg(FStr);
    end;procedure TForm1.DisplayMsg(s: string);
    begin
      memo1.Lines.Add(s)
    end;procedure TForm1.Button1Click(Sender: TObject);
    begin
      ClientSocket1.Active:=true;
    end;procedure TForm1.ClientSocket1Connect(Sender: TObject;
      Socket: TCustomWinSocket);
    begin
      Fo:=TFileStream.Create('d:\test.txt',FmCreate);
    end;procedure TForm1.ClientSocket1Disconnect(Sender: TObject;
      Socket: TCustomWinSocket);
    begin
      Fo.Free;
    end;procedure TForm1.Button2Click(Sender: TObject);
    begin
      ClientSocket1.Active:=false;
    end;end.