怎样写一个获取数据函数:用TCP/IP通讯,向服务端发送命令,并从服务端获得返回数据. Delphi / Windows SDK/APIhttp://www.delphi2007.net/DelphiNetwork/html/delphi_20061126110916251.html
我想编写一个函数getDataFormSerevr(command:string):string;
函数实现的是:用TCP/IP通讯,向服务端发送command,并从服务端获得返回数据作为函数的值.
如何处理等待数据返回的问题?
如何解决超时问题?
希望高手提供解答.
自己设定一个时间,发出指令后,如果到了时间还是一个字也没收到,就提示挂了,请检查网络!如果已经开始收到了,就搞个进度条出来……让大家请稍侯!
先用timer设置一个时间 一般都是500毫秒就够了 用这个时间来处理返回就够了 如果连接不上的话有个返回值写到线程里面去 如果值为-1就是最大~~
我是在一个函数里实现,怎么能用TIMER呢?
首先,基本不用考虑什么超时问题,因为你是先去连接服务器,然后再用这个函数的,tcp连接后除非发生阻塞,一般不会出现问题, 也可以用异常处理来解决
另外,等待数据返回的话,需要用线程来发送和接受
可以使用阻塞通讯模式。下面使我写的同步通讯类单元。
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.
你的函数只需类似这样调用即可:
ST:TQiSocketTransport
...
创建并连接服务器
..
getDataFormSerevr(command:string):string
begin
ST.Send....
ST.Receive.......
end;