这是我从HUBDOG的宝典上找到的。
使用TServerSocket构件提供多线程服务
对于一个socket来说,很容易提供一个侦听消息的多线程服务。Delphi自身也提供了这样的构件:TServerSocket。
不过这里边也需要一点小技巧。
为此,我们要做以下几件事:
-将TServerSocket加入main窗体中
-设置Servertype属性为stThreadBlocking
-生成一个新单元(如下)来包含服务线程
将下面的代码赋给OnGetThread事件响应函数
procedure TfrmMain.fSocketGetThread(Sender: TObject;
ClientSocket: TServerClientWinSocket;
var SocketThread: TServerClientThread);
begin
// 在每次一个新连接建立的时候为它生成一个新的TServerThread对象。
SocketThread := TServerThread.Create( FALSE, ClientSocket );
end;
下面是我自己生成的TServerThread对象代码.该对象从TServerClinetThread继承而来,包含从socket读写数据的代码。
unit serverthread;
interface
uses
windows, scktcomp, SysUtils, Classes, Forms;
type
EServerThread = class( Exception );
// TServerThread服务线程类是TServerClientThread的派生类
TServerThread = class( TServerClientThread )
private
fSocketStream : TWinSocketStream;
public
procedure ClientExecute; override;
// ClientExecute过程将覆盖TServerClientThread.ClientExecute过程
// 并包含实际执行的代码于线程开始时。
end;
implementation
procedure TServerThread.ClientExecute;
begin
inherited FreeOnTerminate := TRUE;
try
fSocketStream := TWinSocketStream.Create( ClientSocket,100000 );
// 设置100000毫秒的充许超时.
try
while ( not Terminated ) and ( ClientSocket.Connected ) do
try
// 在此处加入你对输入、读、写的等待
// 下面的示范你可以拿来照搬在此
except on e:exception do
begin
// 一旦错误发生就关闭并退出
ClientSocket.Close;
Terminate;
end;
end;
finally
fSocketStream.Free;
end;
except on e:exception do
begin
// 一旦错误发生就关闭并退出
ClientSocket.Close;
Terminate;
end;
end;
end;
一旦连接建立,线程需要等待数据到来.你可以使用下面的代码来等待数据:
if ( not Terminated ) and
( not fSocketStream.WaitForData( 1000000 ) ) then
begin
// 超时处理
end;
// 数据到达!
为了读取数据,我们需要建立一个数据缓冲区存取到达的数据,可以使用PByteArray或一个char型的数组.
在此例中我设置了一个名为fRequest的char型数组缓冲。此外我将其设为定长,其大小由REQUESTSIZE常量决定.
var
ac, readlen : integer;
begin
FillChar( fRequest, REQUESTSIZE, 0 );
ac := 0;
repeat
readlen := fSocketStream.Read( fRequest[ac],
1024 );
// 每次读取1024 bytes直到缓冲区满
ac := ac+readlen;
until ( readlen = 0 ) or ( ac = REQUESTSIZE );
end;
如果说readlen是 0 的话,说明我未收到任何数据.读函数的超时从TWinSocketStream.Create()执行后开始.如果说你不知道预期的数据量,你最好将超时设置得尽量小些.在大多数情况下 30 秒是上限.
当发送一个应答时,你应该很清楚客户端的行为.许多客户端仅仅等待一个应答包,一些则等待许多包.
在本例中,我只设置了一个客户端并只等待一个包,所以我们需要一次就将数据包发送出去。
fSocketStream.WriteBuffer( fRep, fReplySize );
fRep是应答缓冲区,fReplySize则是缓冲区大小.