{这是我根据Borland Socket Service改写的类:TListenSocket, 它的功能是相当于:"X:/Program Files/Borland/Delphi5/Bin/scktsrvr.exe"。也是说它可以将你的分布式服务端程序变成一个有侦听功能的程序,有侦听,还有你的Remote DataModule可以照样运行。写出来不久,如果有什么BUG,请指出,谢谢。}
{本想把它做成控件方式的,现在不想去改动了。有需要再说,}
{
用法:
uses Listensocket;
var Socket:TListenSocket;
const ListenPort=8888;
Socket:=TListenSocket.Create(Self);
Socket.ListenPort:=ListPort;
Socket.Open;
//OK
}
unit ListenSocket;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, SConnect,ScktComp,SvcMgr, ActiveX,MidConst,winsock,MyConst;
var FClientThreads:TList;type TSocketDispatcherThread = class(TServerClientThread, ISendDataBlock) private FRefCount: Integer; FInterpreter: TDataBlockInterpreter; FTransport: ITransport; FLastActivity: TDateTime; FTimeout: TDateTime; FRegisteredOnly: Boolean; procedure AddClient; procedure RemoveClient; protected function CreateServerTransport: ITransport; virtual; { procedure AddClient; procedure RemoveClient; } { IUnknown } function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; { ISendDataBlock } function Send(const Data: IDataBlock; WaitForResult: Boolean): IDataBlock; stdcall; public constructor Create(CreateSuspended: Boolean; ASocket: TServerClientWinSocket; const InterceptGUID: string; Timeout: Integer; RegisteredOnly: Boolean); procedure ClientExecute; override; end;
type MyServerSocket=Class(TServerSocket) private procedure GetThread(Sender: TObject; ClientSocket: TServerClientWinSocket;var SocketThread: TServerClientThread); public constructor Create(AOwner: TComponent); override;end;
type TListenSocket = class(TObject) private FActive:Boolean; FListPort :integer; FCacheSize :integer; SH:MyServerSocket; FItemIndex :integer; procedure SetActiveState(Value:boolean); function GetClientCount :integer; { Private declarations } public property CacheSize :integer read FCacheSize write FCacheSize; property ListPort:integer read FListPort write FListPort; property Active :boolean read FActive write SetActiveState; property ClientCount:integer read GetClientCount; public constructor Create(AOwner :TComponent); destructor Destroy;override; class procedure AddClientThread(Thread :TSocketDispatcherThread); class procedure RemoveClientThread(Thread:TSocketDispatcherThread); procedure Open; procedure Close; end;
implementation
function TListenSocket.GetClientCount :integer;begin Result:=FClientThreads.Count;end;
constructor TListenSocket.Create(AOwner :TComponent);begin LoadWinSock2; FActive:=False; FClientCount:=0; FCacheSize :=10; FClientThreads:=TList.Create; SH:=MyServerSocket.Create(nil); inherited Create;end;
destructor TListenSocket.Destroy;begin SetActiveState(False); FreeAndNil(FClientThreahs); inherited Destroy;end;
procedure TListenSocket.Open;begin SetActiveState(True);end;
procedure TListenSocket.Close;begin SetActiveState(False);end;
class procedure TListenSocket.AddClientThread(Thread :TSocketDispatcherThread);begin FClientThreads.Add(Thread);end;
class procedure TListenSocket.RemoveClientThread(Thread :TSocketDispatcherThread);var i:integer;begin for i:=0 to FClientThreads.Count -1 do begin
i:=FClientThreahs.IndexOf(Thread); if i<>-1then FClientThreads.Delete(i); end;end;
procedure TListenSocket.SetActiveState(Value:boolean);var i:integer;begin if Value then begin SH.Close; SH.Port :=ListPort; SH.ThreadCacheSize :=CacheSize; SH.Open; end else if not Value then//if FClientCount>0 then Error('还有客户在连接状态,中止。') SH.Close; FActive:=Value;end;
//下面的东西都是在Delphi中Copy过来的,为我所用了。呵呵
{MyServerSocket Class}procedure MyServerSocket.GetThread(Sender: TObject; ClientSocket: TServerClientWinSocket; var SocketThread: TServerClientThread);begin SocketThread:=TSocketDispatcherThread.Create(false,ClientSocket,'',0,false);end;
constructor MyServerSocket.Create(AOwner: TComponent);begin inherited Create(AOwner); ServerType := stThreadBlocking; OnGetThread := GetThread;end;{MyServerSocket Class over}
{TSocketDispatcherThread class}function TSocketDispatcherThread.CreateServerTransport: ITransport;var SocketTransport: TSocketTransport;begin SocketTransport := TSocketTransport.Create; SocketTransport.Socket := ClientSocket; Result := SocketTransport as ITransport;end;
constructor TSocketDispatcherThread.Create(CreateSuspended: Boolean; ASocket: TServerClientWinSocket; const InterceptGUID: string; Timeout: Integer; RegisteredOnly: Boolean);begin FTimeout:=EncodeTime(Timeout div 60, Timeout mod 60, 0, 0); FRegisteredOnly:=RegisteredOnly; FLastActivity:=Now; inherited Create(CreateSuspended, ASocket);end;
function TSocketDispatcherThread.Send(const Data:IDataBlock; WaitForResult:Boolean):IDataBlock;begin FTransport.Send(Data); if WaitForResult then while True do begin Result := FTransport.Receive(True, 0); if Result = nil then break; if (Result.Signature and ResultSig) = ResultSig then break else FInterpreter.InterpretData(Result); end;end;
procedure TSocketDispatcherThread.AddClient;begin TListenSocket.AddClientThread(Self);end;
procedure TSocketDispatcherThread.RemoveClient;begin TListenSocket.RemoveClientThread(Self);end;
procedure TSocketDispatcherThread.ClientExecute;var Data: IDataBlock; msg: TMsg; Obj: ISendDataBlock; Event: THandle; WaitTime: DWord;begin CoInitialize(nil); try Synchronize(AddClient); FTransport := CreateServerTransport; try Event := FTransport.GetWaitEvent; PeekMessage(msg, 0, WM_USER, WM_USER, PM_NOREMOVE); GetInterface(ISendDataBlock, Obj); if FRegisteredOnly then FInterpreter := TDataBlockInterpreter.Create(Obj, SSockets) else FInterpreter := TDataBlockInterpreter.Create(Obj, ''); try Obj := nil; if FTimeout = 0 then WaitTime := INFINITE else WaitTime := 60000; //MAXIMUM_WAIT_OBJECTS while not Terminated and FTransport.Connected do try case MsgWaitForMultipleObjects(1, Event, False, WaitTime, QS_ALLEVENTS) of WAIT_OBJECT_0: begin WSAResetEvent(Event); Data := FTransport.Receive(False, 0); if Assigned(Data) then begin FLastActivity := Now; FInterpreter.InterpretData(Data); Data := nil; FLastActivity := Now; end; end; WAIT_OBJECT_0 + 1: while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do DispatchMessage(msg); WAIT_TIMEOUT: if (FTimeout > 0) and ((Now - FLastActivity) > FTimeout) then FTransport.Connected := False; end; except FTransport.Connected := False; end; finally FInterpreter.Free; FInterpreter := nil; end; finally FTransport := nil; end; finally CoUninitialize; Synchronize(RemoveClient); end;end;
function TSocketDispatcherThread.QueryInterface(const IID: TGUID; out Obj): HResult;begin if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE;end;
function TSocketDispatcherThread._AddRef: Integer;begin Inc(FRefCount); Result := FRefCount;end;
function TSocketDispatcherThread._Release: Integer;begin Dec(FRefCount); Result := FRefCount;end;{TSocketDispatcherThread class over}
end.