我想编写一个函数getDataFormSerevr(command:string):string;
函数实现的是:用TCP/IP通讯,向服务端发送command,并从服务端获得返回数据作为函数的值.
如何处理等待数据返回的问题?
如何解决超时问题?
希望高手提供解答.

解决方案 »

  1.   

    先用timer设置一个时间 一般都是500毫秒就够了 用这个时间来处理返回就够了 如果连接不上的话有个返回值写到线程里面去 如果值为-1就是最大~~
      

  2.   

    我是在一个函数里实现,怎么能用TIMER呢?
      

  3.   

    首先,基本不用考虑什么超时问题,因为你是先去连接服务器,然后再用这个函数的,tcp连接后除非发生阻塞,一般不会出现问题, 也可以用异常处理来解决
    另外,等待数据返回的话,需要用线程来发送和接受
      

  4.   

    可以使用阻塞通讯模式。下面使我写的同步通讯类单元。
    unit RCUnit;interface
    uses Windows, SysUtils, WinSock, ComObj, ScktComp,SConnect;type
      ESocketConnectionError = class(Exception);  TQiSocketTransport = class(TInterfacedObject)
      private
        FEvent: THandle;
        FAddress: string;
        FHost: string;
        FPort: Integer;
        FClientSocket: TClientSocket;
        FSocket: TCustomWinSocket;
      protected
        { ITransport }
        function GetWaitEvent: THandle; stdcall;
        function GetConnected: Boolean; stdcall;
        procedure SetConnected(Value: Boolean); stdcall;
        function Receive(WaitForInput: Boolean;Buffer:Pointer):Integer; stdcall;
        function Send(Buffer:Pointer;Count:Integer): Integer; stdcall;
      public
        constructor Create;
        destructor Destroy; override;
        property Connected:Boolean read GetConnected write SetConnected;
        property Host: string read FHost write FHost;
        property Address: string read FAddress write FAddress;
        property Port: Integer read FPort write FPort;
        property Socket: TCustomWinSocket read FSocket write FSocket;
      end;
    implementation
    const
      SIG_EXCEPTION:Integer=$EEEEEEEE;
      SIG_OK   :Integer    =$00000000;
      ESocketReadError     ='Socket read error.';
      ENoAddress     ='No address.';  var
      hWinSock2: THandle;  WSACreateEvent: function: THandle stdcall;
      WSAResetEvent: function(hEvent: THandle): Boolean stdcall;
      WSACloseEvent: function(hEvent: THandle): Boolean stdcall;
      WSAEventSelect: function(s: TSocket; hEventObject: THandle; lNetworkEvents: Integer): Integer stdcall;
    function CheckSignature(Sig:Integer):Boolean;
    begin
      if Sig=SIG_EXCEPTION then
        Raise Exception.Create('Remote call error!')
      else
        Result:=True;
    end;{ TQiSocketTransport }constructor TQiSocketTransport.Create;
    begin
      inherited Create;
      FEvent := 0;
    end;destructor TQiSocketTransport.Destroy;
    begin
      SetConnected(False);
      inherited Destroy;
    end;function TQiSocketTransport.GetWaitEvent: THandle;
    begin
      FEvent := WSACreateEvent;
      WSAEventSelect(FSocket.SocketHandle, FEvent, FD_READ or FD_CLOSE);
      Result := FEvent;
    end;function TQiSocketTransport.GetConnected: Boolean;
    begin
      Result := (FSocket <> nil) and (FSocket.Connected);
    end;procedure TQiSocketTransport.SetConnected(Value: Boolean);
    begin
      if GetConnected = Value then Exit;
      if Value then
      begin
        if (FAddress = '') and (FHost = '') then
          raise ESocketConnectionError.Create(ENoAddress);
        FClientSocket := TClientSocket.Create(nil);
        FClientSocket.ClientType := ctBlocking;
        FSocket := FClientSocket.Socket;
        FClientSocket.Port := FPort;
        if FAddress <> '' then
          FClientSocket.Address := FAddress else
          FClientSocket.Host := FHost;
        FClientSocket.Open;
      end else
      begin
        if FSocket <> nil then FSocket.Close;
        FSocket := nil;
        FreeAndNil(FClientSocket);
        if FEvent <> 0 then WSACloseEvent(FEvent);
        FEvent := 0;
      end;
    end;function TQiSocketTransport.Receive(WaitForInput: Boolean;Buffer:Pointer):Integer; stdcall;var
      RetLen, Sig, StreamLen: Integer;
      P: Pointer;
      FDSet: TFDSet;
      TimeVal: PTimeVal;
      RetVal: Integer;
      bFirst: boolean;begin
      Result := 0;
      TimeVal := NIL;
      FD_ZERO(FDSet);
      FD_SET(FSocket.SocketHandle, FDSet);
      if not WaitForInput then
      begin
        New(TimeVal);
        TimeVal.tv_sec := 0;
        TimeVal.tv_usec := 1;
      end;
      RetVal := select(0, @FDSet, nil, nil, TimeVal);
      if Assigned(TimeVal) then
        FreeMem(TimeVal);
      if RetVal = SOCKET_ERROR then
        raise ESocketConnectionError.Create(SysErrorMessage(WSAGetLastError));
      if (RetVal = 0) then Exit;  RetLen := FSocket.ReceiveBuf(Sig, SizeOf(Sig));
      if RetLen <> SizeOf(Sig) then
        raise ESocketConnectionError.Create(ESocketReadError);
      CheckSignature(Sig);
      RetLen := FSocket.ReceiveBuf(StreamLen, SizeOf(StreamLen));
      if RetLen = 0 then
        raise ESocketConnectionError.Create(ESocketReadError);
      if RetLen <> SizeOf(StreamLen) then
        raise ESocketConnectionError.Create(ESocketReadError);
      P := Buffer;
      if (StreamLen > 0) then  WaitForSingleObject(FEvent, {INFINITE}60000);
      bFirst := True;  while StreamLen > 0 do
      begin
        RetLen := FSocket.ReceiveBuf(P^, StreamLen);
        if RetLen = 0 then
        begin
          if not bFirst then
              raise ESocketConnectionError.Create(ESocketReadError);      bFirst := False;
        end;    if RetLen > 0 then
        begin
          Dec(StreamLen, RetLen);
          Inc(Integer(P), RetLen);
        end;    if StreamLen > 0 then
        begin
          if (WaitForSingleObject(FEvent, {INFINITE}90000) = WAIT_OBJECT_0) then
          begin
            WSAResetEvent(FEvent);
          end
          else
          begin
            raise ESocketConnectionError.Create('Read Error Single Object Timeout');
          end;
        end;  end;
      if StreamLen <> 0 then
        raise ESocketConnectionError.Create(ESocketReadError);
    end;function TQiSocketTransport.Send(Buffer:Pointer;Count:Integer): Integer; stdcall;
    var
      Size:Integer;
    begin
      Result := 0;
      Size:=Count;
      if Size>0 then
      begin
        FSocket.SendBuf(Buffer^, Count);
      end;
    end;function LoadWinSock2: Boolean;
    const
      DLLName = 'ws2_32.dll';
    begin
      Result := hWinSock2 > 0;
      if Result then Exit;
      hWinSock2 := LoadLibrary(PChar(DLLName));
      Result := hWinSock2 > 0;
      if Result then
      begin
        WSACreateEvent := GetProcAddress(hWinSock2, 'WSACreateEvent');
        WSAResetEvent := GetProcAddress(hWinSock2, 'WSAResetEvent');
        WSACloseEvent := GetProcAddress(hWinSock2, 'WSACloseEvent');
        WSAEventSelect := GetProcAddress(hWinSock2, 'WSAEventSelect');
      end;
    end;initialization
      LoadWinSock2;
    end.
      

  5.   

    你的函数只需类似这样调用即可:
    ST:TQiSocketTransport
    ...
    创建并连接服务器
    ..getDataFormSerevr(command:string):string
    begin 
      ST.Send....  
      ST.Receive.......
    end;