我在Delphi 5下基于TCP/IP用ClientSocket和ServerSocket进行非阻塞通信,客户端发出数据请求,服务器接到请求后在库里查询记录并返回(一条记录为一包,大小在140个字节左右,通常为几千个包,服务器端已经固定,我无法修改,只能修改客户端),但我的客户端接收到的数据与我所期望的并不一致(表现为不稳定,有时处理成功有时失败),不知道究竟是服务器发包不对还是我的处理代码有问题,请大虾们帮我看看如下的代码:
type
  TPackHeader =packed record
    len : longint;             //包的总长度,为包头和包体长度总和
    morepkt : char;                        //1:有后续包 0:无
    sequence : longint;                    //包序号
    errorcode : smallint;                  //返回码
  end;
type
  TPackage=packed record
    PackHeader : TPackHeader;         //包头
    datatrans : array[0..0] of char; //传送内容,从datatrans开始,    end;                                 //实际使用时取其地址作为指针使用
  TPPackage=^TPackage;
const PackHeadSize=11;
var
 ErrorInfo:string;
 templist:TStringList; 
procedure Tfrm_Progress.ClientSocket1Read(Sender: TObject;
  Socket: TCustomWinSocket);
var
DataTrans:array[0..2048-1] of char;
Data:string;
PackHeader:TPackHeader;
tempSize:integer;
BodySize:integer;
P:Pointer;
RecLen:Integer;
begin
 while true do            //去掉while循环还是有问题 
 begin
  if socket.ReceiveLength<=PackHeadSize then continue;//去掉该句还是有问题
  fillchar(PackHeader,sizeof(PackHeader),#0);
  tempSize:=0;      
  while tempSize<PackHeadSize do
  begin
   P:=pointer(integer(@PackHeader)+tempSize);
   RecLen:=socket.ReceiveBuf(p^,PackHeadSize-tempSize);
   if RecLen>0 then
     tempSize:=tempSize+RecLen
   else
     delay4(0,0,0,1);  
  end;
  DataTrans:=#0;
  BodySize:=PackHeader.len-PackHeadSize;
  tempSize:=0;    
  while tempSize<BodySize do
  begin
   RecLen:=socket.ReceiveBuf(DataTrans[tempSize],BodySize-tempSize);
   if RecLen > 0 then
     tempSize:=tempSize+RecLen
   else
     delay4(0,0,0,1);
  end;
  Data:=copy(PChar(@DataTrans),0,PackHeader.len-PackHeadSize);
 //DataTrans数组中的有效数据无#0,最后一个字符才为#0,故copy该句应该没问题  
  if PackHeader.errorcode<>0 then       //如果查询出错
  begin
    ErrorInfo:='Error!'; //有时程序从这里退出,说明接到的包数据乱了,??    
    Exit;  
  end;    
  templist.Add(Data);
  if (PackHeader.morepkt = '0') then
  begin
    ErrorInfo:='Complete!';
    ProcessData();//数据包全部接收完,开始进行处理,提取各字段写入数据库操作
    exit;
  end;         
end;  //延时函数
procedure Tfrm_Progress.Delay4(Hour,Min,Sec,MSec:word);
var timeout:TDateTime;
begin
  timeout:=now+encodeTime(Hour,Min,Sec,MSec);
  While now<timeout do
    Application.ProcessMessages;
end;
分全给了,请高手指点是否代码可行?如果不,请给出一个类似处理的例子(有服务器端代码更好),另外,有什么办法可以一边接收一边ProcessData()处理数据而保证不会出错?很急很急,万万分感谢!!!

解决方案 »

  1.   

    我是楼主,刚才漏写了一个与while循环的begin对应的end ,请大家注意!
      

  2.   

    公网?局网?如是局网我有一个,公网上我也正在???。能否将你的源码发到[email protected]
    谢谢!
      

  3.   

    楼主对您提的问题我回答不了,但我想你是高手了
    ,我想问一个我的问题如下:(问题现象是:为什么接收到的数据与发出去的不符,而且还出现内存访问错误(使用TSeverSocket与TClientSocket))定义如下数据结构:type Block=record     Num:integer;//块在块列表的序号
         ScrRect:iScrRect;//对应的屏幕矩形
         UserName:string;//计算此块的计算机名
         UserIP:string;//计算此块的计算机IP
         UserSocketID:integer;//计算此块的Socket连接句柄
         DispatchedTime:string;//被分配出去的时间
         CompletetTime:string;//计算完成的时间
    end;
    type CalPara=record//定义发送给Client端的计算参数的消息数据结构
        cMin:ePoint;
        sDCX:extended; //复数实部变化步长
        sDCY:extended;//复数虚部变化步长
        iMaxLoopNum:integer;//最大迭代次数
        iBoarder:extended; //吸引子
    end;
    type AllCalInfo=record
         BlockInfo:Block;
         CurCalPara:CalPara;
    end;发送端:
    function getAllCalInfo(var ACI:AllCalInfo):boolean;begin
     if BlockNum<>-1 then
     begin  ACI.BlockInfo:=Blocks[BlockNum];  ACI.CurCalPara.cMin.X:=StrToFloat(FrmServer.LedtcXMin.Text);
      ACI.CurCalPara.cMin.Y:=StrToFloat(FrmServer.LedtcYMin.Text);  ACI.CurCalPara.sDCX:=  (strToFloat(FrmServer.LedtcXMax.Text)-StrToFloat(FrmServer.LedtcXMin.Text))/FrmServer.SpWidth.Value;
      ACI.CurCalPara.sDCY:=
      (StrToFloat(FrmServer.LedtcYMax.Text)-StrToFloat(FrmServer.LedtcYMin.Text))/FrmServer.SpHeight.Value;
      ACI.CurCalPara.iMaxLoopNum:=FrmServer.SpNum.Value;
      ACI.CurCalPara.iBoarder:=FrmServer.SpXYZ.Value;
       result:=true;
     end else result:=false;end;
      
    var Info:^AllCalInfo;
      
    begin
       GetMem(Info,SizeOf(blocks[0]));
    if  getAllCalInfo(Info^) then
    begin
      
     SendNum:=Socket.SendBuf(Info,sizeOf(AllCalInfo)); 
    end else showmessage('发生意外,不能取得计算信息!')end;Client端:var
     re:pchar;
     CalInfo:^AllCalInfo;
     sbuf:string;
     relong:integer;
     
    begin
     
          // ShowMessage(inttostr(Sizeof(AllCalInfo)));     reLong:=Socket.ReceiveLength;
         GetMem(CalInfo,reLong);   
        ZeroMemory(CalInfo,reLong);
       Socket.ReceiveBuf(CalInfo,reLong);    if CalInfo^.BlockInfo.Num >-1 then//在这里查看CalInfo^的数据,发现与发送的不同
        begin
          Echo.Lines.Add('得到任务...');
        end;
      end;
    end;
    在线等待!!!
      

  4.   

    通讯里最好用packet record,和C++等其它语言的结构一致,否则存在字节对齐问题
      

  5.   

    数据是不会掉失的,只是由于网络的问题,在传输过程中,系统处理的数据包并不是等于你发的数据包的大小.如你发出去是5K,系统可能分两次发送这个包,第一个是1K,第2个是4K.
    所以你在服务器里一定要有判断,并把重新把两个包串起来.得到你要的数据结构