最近在写一个小程序,客户端用Delphi编写,通过Socket与Java编写的服务端通讯。基本上都是一收一发,比如系统登录,客户端将用户名、密码送到服务端,然后等待服务端返回,服务端收到后验证用户名、名称,再将结果返回给客户端。还有一种情况是服务端主动向客户端发请求,客户端在接收到请求后触发相应的事件。
我自己写了一个线程,在线程内接收/发送Socket,代码见mySocketThread.pas。
在主窗体内放一个Indy的TcpClient,然后执行以下代码,程序就能跑起来了:
////////////////////连接服务端/////////////////////////
var myThread: TmySocketThread;   With IdTCPClient1 do
   begin
      Host := edServerAddr.Text;
      Port := StrToInt(edServerPort.Text);
      Try
         Connect;
      except
         On E:Exception do
         begin
            WriteLog('在连接服务器时发生错误,错误消息:' + E.Message);
            Exit;
         end;
      end;
      //在这里创建线程,将Socket传进去
      myThread := TmySocketThread.Create(False,IdTCPClient1.Socket);
      WriteLog('服务器连接成功!');
   end;
////////////////////发送/接收数据/////////////////////////
Var
   sMsg: String
begin
   sMsg := '<message><command>Login</command>...</message>'
   if Not myThread.SendData(sMsg) then //发送
   begin
      ShowMessage('发送失败');
   end;
   if Not myThread.WaitFor('LoginResp',10,sLocalMsg) then //等待服务器返回结果,如果10秒后服务器还没有返回,则报错。
   begin
      ShowMessage('服务器没有返回请求结果');
   end;
end;程序能正常执行,发送/接收数据都能正常,只是目前碰到一个问题:有时候(注意只是有时候,不定期的)程序会报错,或者没有报错直接退出了,报错的时候报的错误是“Exception EInvalidPointer in modul QHQL.exe  at 0015C469. Invalid pointer operaton”,这种情况一般都发生在我请求非常频繁时,比如我循环100次,不停地向服务器发送登录请求,就会出现这种错误。请各位DX帮忙解决一下。解决后立即再开一帖送分。

解决方案 »

  1.   

    //////////////////////////////mySocketThread.pas////////////////////////////
    unit mySocketThread;interfaceuses
      Variants, Graphics, Controls, Forms,Dialogs,
      Classes, Windows ,WinSock,ScktComp, Messages, SysUtils,IdAntiFreezeBase, IdAntiFreeze,
      IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,IdIOHandlerSocket,SyncObjs;type
       PMyPack = ^TMyPack;
       TMyPack = packed record
          OrgID: Word;           //送端主机编码
          OrgPort: Word;         //发送端通信端口号
          DestID: Word;          //接收端主机编码
          DestPort: Word;        //接收端通信端口号
          PackLen: Word;         //xml包体的长度
          PacketType: Byte;      //包类型标识:0x00-单独包,0x01-拆分包的中间包,0x02-拆分包的最后一个包
          SubPacketSNO: Byte;    //拆分包的包序号,从1开始计数,最大只允许255个包
          PacketSNO: Word;       //包序号,用于一个包拆分之前的计数
          PacketCodeType: Byte;  //包编码类型:ucsp为0,client为1,wap为2,web为3,pda为4
          Reserved: Byte;        //保留,保证包头大小为4的整数倍
       end;type
      TmySocketThread = class(TThread)
      private
        mySocket:TIdIOHandlerSocket;
      protected
        procedure Execute; override; //读取  public
        Constructor Create(CreateSuspended: Boolean;Sock:TIdIOHandlerSocket);
        function ProcessCmd(sMsg: string): Boolean; //处理收到的消息
        function SendData(sMsg:String):Boolean;virtual; //发送
        Function WaitFor(Flag:String;iTimeOut:Integer;Var sLocalMsg:String):Boolean; //等待预期的结果;
      end;implementationUses Share,FunPublic,unMain;{ TSockThread }
    constructor TmySocketThread.Create(CreateSuspended: Boolean;
      Sock: TIdIOHandlerSocket);
    begin
       Inherited Create(CreateSuspended);
       FreeOnTerminate:=True;
       mySocket := Sock;
    end;{destructor TmySocketThread.Destroy;
    begin
       Try
          if Assigned(mySocket) then
          begin
             mySocket.Free;
             mySocket := nil;
          end;
       Except
       end;
       inherited;
    end;}procedure TmySocketThread.Execute;
    Var
    pHeadBuf,pBodyBuf:PChar;
       iHeadLen,iBodyLen:Integer;
       myPack:PMyPack;
       sMsg:String;
    begin
       pHeadBuf := nil; pBodyBuf := nil;
       iHeadLen := SizeOf(TMyPack);
       While (Not Terminated) do
       begin
          if Not Assigned(mySocket) then
          begin
             WriteLog('mySocket Not Assigned! App Exit...');
             Synchronize(frmMain.ForceExit);
             Exit;
          end;
          if Not mySocket.Connected then
          begin
             WriteLog('mySocket Not Connected! App Exit...');
             Synchronize(frmMain.ForceExit);
          end;
          GetMem(pHeadBuf,iHeadLen);
          Try
             Try
                mySocket.Recv(pHeadBuf^,iHeadLen); //先读取包头
                myPack := PMyPack(pHeadBuf); //解析出包头
                iBodyLen := myPack^.PackLen; //得到包体的长度
                if iBodyLen > 0 then
                begin
                   //再读取包体
                   if pBodyBuf = nil then GetMem(pBodyBuf,iBodyLen);
                   if Not Assigned(pBodyBuf) then
                   begin
                      WriteLog('GetMem Error! App Exit...');
                      Synchronize(frmMain.ForceExit);
                   end;
                   mySocket.Recv(pBodyBuf^,iBodyLen);
                   SetLength(sMsg, iBodyLen);
                   StrCopy(PChar(sMsg), pBodyBuf);
                   if not ProcessCmd(sMsg) then
                   begin
                      WriteLog('ProcessCmd Error! App Exit...');
                      Synchronize(frmMain.ForceExit);
                   end;
                end;
             Except
                On E:Exception do
                begin
                   WriteLog('Socket Read Data Error! ErrorMsg:'+ E.Message + 'App Exit...');
                   Synchronize(frmMain.ForceExit);
                end;
             end;
          Finally
             Try
                if Assigned(pHeadBuf) then
                begin
                   FreeMem(pHeadBuf);
                   pHeadBuf := nil;
                end;
                if Assigned(pBodyBuf) then
                begin
                   FreeMem(pBodyBuf);
                   pBodyBuf := nil;
                end;
                myPack := nil;
             Except
             end; 
          end;
          //Sleep(100);
          //Application.ProcessMessages;
       end;
    end;function TmySocketThread.SendData(sMsg: String): Boolean;
    Var
       sBody:String;
       myPack:^TMyPack;
       pBuf:Pchar;
       BodyLen, PackLen:integer;
    begin
       pBuf := nil;
       if Not Assigned(mySocket) then
       begin
          WriteLog('SendData: mySocket No Assigned! App Exit...');
          Synchronize(frmMain.ForceExit);
       end;
       if Not mySocket.Connected then
       begin
          WriteLog('SendData: mySocket Not Connected! App Exit...');
          Synchronize(frmMain.ForceExit);
       end;
       
       sBody := sMsg;   BodyLen := Length(sBody);
       PackLen := BodyLen + SizeOf(TMyPack);   New(myPack);
       FillMemory(myPack, SizeOf(myPack^), 0);
       myPack.OrgID := 1;
       myPack.OrgPort := 1;
       myPack.DestID := 1;
       myPack.DestPort := 1;
       myPack.PackLen := BodyLen;
       myPack.PacketType := 0;
       myPack.SubPacketSNO := 1;
       myPack.PacketSNO := 1;
       myPack.PacketCodeType := 1;
       myPack.Reserved := 0;   if pBuf = nil then GetMem(pBuf, PackLen);
       if not Assigned(pBuf) then
       begin
          WriteLog('GetMem Error! App Exit...');
          Synchronize(frmMain.ForceExit);
       end;
       
       Try
          Try
             CopyMemory(pBuf, myPack, SizeOf(TMyPack));
             CopyMemory(pBuf+SizeOf(TMyPack),@sBody[1], BodyLen);
             mySocket.Send(pBuf^,PackLen);
             ReceiveMsg := '';
             ReceiveCmd := '';
             {$ifDef _COMMLOG}
                WriteLog(sMsg);
             {$endif}
             Result := True;
          Except
             Result := False;
             WriteLog('Send Data Error! App Exit...');
             Synchronize(frmMain.ForceExit);
          end;
       Finally
          if Assigned(pBuf) then
          begin
             FreeMem(pBuf);
             pBuf := nil;
          end;
          myPack := nil;
       end;
       Sleep(200);
       //Application.ProcessMessages;
    end;function TmySocketThread.WaitFor(Flag: String; iTimeOut: Integer;Var sLocalMsg:String): Boolean;
    Var
       iInit: Integer;
    begin
       iInit := 0;
       sLocalMsg := '';
       While iInit < iTimeOut*1000 do
       begin
          if UPPERCASE(Flag) = UPPERCASE(ReceiveCmd) then
          begin
             sLocalMsg := ReceiveMsg; 
             Result := True;
             Exit;
          end
          else
          begin
             Synchronize(Application.ProcessMessages);
             Sleep(100);
          end;
          iInit := iInit + 100;
       end;
       Result := False;
    end;function TmySocketThread.ProcessCmd(sMsg: string): Boolean;
    Var
       sIsResult : String;
    begin
       Result := True;
       sIsResult := GetPackContent('isresult', sMsg);
       if uppercase(sIsResult)=uppercase('true') then //服务端根据客户端发出请求返回的响应信息;
       begin
          ReceiveMsg := sMsg;
          ReceiveCmd := GetPackContent('command', sMsg);
          {$ifDef _COMMLOG}
             WriteLog('Receive From Server Command=' + ReceiveCmd + ',ReceiveMsg=' + ReceiveMsg);
          {$endif}
       end
       else
       begin //服务端主动发过来的消息,需要根据消息内容触发相应的事件;
          {$ifDef _COMMLOG}
             WriteLog('Receive From Server:' + sMsg);
          {$endif}
       end;
    end;end.
      

  2.   

    提供一些建议:先打开工程的所有编译选项project-〉options-〉compiler,然后在调试状态下运行程序。等待出错。(其间可以用codesite等工具记录事件和变量)。确定出错时调用的语句和变量,在检查各个变量的值得变化过程。直到找到错误。