初学socket编程,自己写了一个简单的ctNonBlocking程序,想法是把sever发来的数据连接在一起,存储在array中,程序段如下
procedure TForm1.RemoteSocketRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  temp: array [0..500] of byte;
  length:integer;
  i:integer;
begin  length:=RemoteSocket.Socket.ReceiveLength;
  RemoteSocket.Socket.ReceiveBuf(temp,length);  for i:=msgIn_length to msgIn_length+length do
    msgIn[i]:=temp[i-msgIn_length];  msgIn_length:=msgIn_length+length;//测验用的显示代码
  for i:=0 to msgIn_lengthNow do
    Memo.Lines.Add(Inttostr(msgIn[i]));
end;可是该段代码无法正常工作,当sever连续发送报文过来,在memo中只显示了第一报文的一部分~然后程序就卡住了~弹出错误。我分析是delphi执行速度不够快,第一段报文还没有保存显示完,第二段就发过来造成这种线程之间的错误。不知该如何解决这种问题~望高手指点。~如果我采用ctBlocking模式~我该如何知道server段有报文发过来呢?然后主动去读。还是说我应该不断读socket,读不到东西就代表server没有报文法给我??

解决方案 »

  1.   

    你说的这种可能性不大,如果你没有别的程序在运行的话。缓冲区有8K呢,不过有一点你需要注意。你声明的Temp只能放500个字节,你确定够吗?即使你的服务器一次只发一行,但你收时是有可能一次收到很多行的。所以这个地方应该昌
    temp: PByte;
    begin
      length := RemoteSocket.Socket.RecivieLength;
      GetMem(temp,length);
      RemoteSocket.Socket.ReceiveBuf.....  FreeMem(temp)其它错误没看出来,好象只有这个地方有可能出错。
      

  2.   

    看法:
    1,socket是从参数传入的,用RemoteSocket.Socket有错。
    2,一定要取得Socket.ReceiveBuf的返回值,它才是实际读出的。
    3,静态分配有限的temp空间没有问题。
    4,一次OnRead事件处理中,最好应该多次ReceiveBuf直到读不出更多数据。
    5,Socket.ReceiveLength的值不太可靠,最好别用。
      

  3.   

    to halfdream(哈欠)在我的程序中,实现文件的远程备份.一般有好几百M之多吧,鉴于文件的重要性,我们采用了TCP,我采用的是TClientSocket的非noBlocking,现在碰到的问题就是在备份当中会有IP数据包丢失(底层本身),如果用对等网是没问题的.你说怎么可以避免呢?
    [email protected]
      

  4.   

    TCP本身已经已经基本保证了一个可靠的数据流.就算是IP少量丢包,TCP层也可以不丢失数据.
    大多数情况下是编制SOCKET程序的时候,对SOCKET的机制了解不够.
    其实有些东西做起来也不难,
    比如OnRead事件中,不要根据Socket.ReceiveLength作什么判断,
    因为它的值不精确.就ReceiveBuf读,从它的返回值中即可取得可靠数据长度.
    对于传几百M的文件,因为传输时间可能比较长,尽管TCP本身保证了不受IP丢包损失数据影响,
    仍有可能链路断掉.
    可以自定义一个协议.文件分块传,标识出文件名,文件块偏移,文件块长度.
      

  5.   

    对于程序来说,应当根据ReceiveLength来初始化你用来读取的缓冲区的大小,实际的数据处理则根据返回的实际读出的数据的多少进行。
    如果你要传几百M的文件的话,那么最好采用阻塞式。这样比较容易处理。
      

  6.   

    procedure TForm1.RemoteSocketRead(Sender: TObject;
      Socket: TCustomWinSocket);
    var
      temp: array [0..500] of byte;
      length:integer;
      i:integer;
    begin  length := Socket.ReceiveLength;
      Lenght := Socket.ReceiveBuf(temp,length);  for i:=msgIn_length to msgIn_length+length do
        msgIn[i]:=temp[i-msgIn_length];  msgIn_length:=msgIn_length+length;//测验用的显示代码
      for i:=0 to msgIn_lengthNow do
        Memo.Lines.Add(Inttostr(msgIn[i]));
    end;
      

  7.   

    //正好回另一个贴子时候写了这个,顺便贴上来.unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, ScktComp, StdCtrls;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);
        procedure FormCreate(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;procedure TForm1.FormCreate(Sender: TObject);
    begin
      Canvas.StretchDraw();
    end;end.
      

  8.   

    不好意思,FORMCREATE事件那一句该去掉.
      

  9.   

    to halfdream(哈欠)3x.
    主要是现在我们已经定义了我们自己通信的协议了,数据总大小是无法知道的,而
    每次传4K,后来用Iris拦截数据包分析得到:
    4k中的第一个IP包乱掉了.这种情况我们要求重新发送此包(自己定义的协议要求).
    这样好了几包后,又会出现这种情况了.
    所以现在的情况是想找到一个妥善的解决办法或者处理机制来保证数据包的传输.
      

  10.   

    tongdings(痛定)
    IP包是少不了要丢失或错误的..这没关系.
    你们自己定义的通信协议总不会直接就架在IP层的基础上吧?IP包的乱掉,可能会造成TCP上发的应用数据块延迟,造成误码的机率倒实在很小.在这儿用'包'这词,出现层次上的混淆,倒不如称为数据块.
    你的意思把文件拆成4K左右的报文,一个报文一个报文的发?
    呵.这样实现机制可以参照一下TCP实现的原理方面的.