L
leaber
Unregistered / Unconfirmed
GUEST, unregistred user!
WSAASYNCSelect 开发之无窗体句柄解决方案
leaber
WSAASYNCSelect 简单易用,但是开发的时候需要相应的句柄来进行消息传递,
当然用FORM的句柄是最简便的,如果没有FORM如何解决:
1、增加一个HANDLE属性和相应的方法
2、为一个没有HANDLE的类加入消息处理功能,
3、增加一个消息分发的过程。
剩下就可以直接在类里面要处理消息的方法。
TSERVERSOCKET里面的实现就用到这种方式,记不太清了。
}
unit WsaServer;
interface
uses
SysUtils, Windows, Messages, Classes, Graphics, Controls,
Forms, Dialogs, Winsock;
const WM_Server = WM_USER + 5;
type
TSockets = array[1..64] of TSocket;
TConnectEvent = procedure (Sender: TObject) of object;
TReadEvent = procedure (Sender: TObject; Buffer: string;Skt:TSocket) of
object;
TWsaServer = class(TObject)
private
FCurrSocket: TSocket;
FHandle: THandle;
FNum: Integer;
FOnConnectEvent: TConnectEvent;
FOnReadEvent: TReadEvent;
FServerSocket: TSocket;
FSockAddr: TSockAddrIn;
FSockets: TSockets;
FWorkFlag: Boolean;
FWsaData: TWsaData;
function GetHandle: THandle;
function GetHost: string;
function GetPort: Integer;
function GetSockets(index:integer): TSocket;
procedure SetHost(const Value: string);
procedure SetPort(Value: Integer);
protected
procedure ProcessMsg(var Msg: TMessage); message WM_Server;
procedure WndProc(var Message: TMessage);
public
constructor Create;
destructor Destroy; override;
procedure SendMsg(MyMsg: string); virtual;
procedure Start; virtual;
procedure Stop; virtual;
procedure WorkIt; virtual;
property CurrSocket: TSocket read FCurrSocket;
property Handle: THandle read GetHandle;
property Host: string read GetHost write SetHost;
property Port: Integer read GetPort write SetPort;
property Sockets[index:integer]: TSocket read GetSockets;
published
property OnConnectEvent: TConnectEvent read FOnConnectEvent write
FOnConnectEvent;
property OnReadEvent: TReadEvent read FOnReadEvent write FOnReadEvent;
end;
implementation
{
********************************** TWsaServer **********************************
}
constructor TWsaServer.Create;
begin
if WSAStartUp($0202,FWsaData)<>0 then
Exception.Create('Init WINSOCK.DLL failed with'+ inttostr(WSAGetLastError()));
FNum:=0;
ZeroMemory(@FSockAddr,SizeOf(FSockAddr));
end;
destructor TWsaServer.Destroy;
begin
if FHandle <> 0 then
DeallocateHWnd(FHandle);
end;
function TWsaServer.GetHandle: THandle;
begin
if FHandle = 0 then
FHandle := AllocateHwnd(WndProc);
//这里实现了虚拟窗口,为以后的消息响应做准备
Result := FHandle;
end;
function TWsaServer.GetHost: string;
begin
Result:=inttostr(ntohs(FSockAddr.sin_addr.S_addr ));
end;
function TWsaServer.GetPort: Integer;
begin
Result:=ntohs(FSockAddr.sin_port);
end;
function TWsaServer.GetSockets(index:integer): TSocket;
begin
end;
procedure TWsaServer.ProcessMsg(var Msg: TMessage);
var
Event: Word;
Sa: TSockAddrin;
i: Integer;
Client: TSocket;
RecvBuffer: string;
begin
Event := Word(Msg.LParam);
case Event of
FD_ACCEPT:
begin
i:=SizeOf(Sa);
Client:=Accept(FServerSocket,@Sa,@i);
if Client=INVALID_SOCKET then
Exception.Create('Client Accept failed error with '+ inttostr(WSAGetLastError()));
WSAAsyncSelect(Client,Handle,WM_Server,FD_READ or FD_CLOSE);
FNum:=FNum+1;
FSockets[FNum]:=Client;
FCurrSocket:=Client;
end;
FD_READ:
begin
FCurrSocket:=TSocket(Msg.WParam );
SetLength(RecvBuffer,1024);
i:=Recv(FCurrSocket,RecvBuffer[1],1024,0);
if Assigned(OnReadEvent) then
OnReadEvent(nil,RecvBuffer,CurrSocket);
end;
FD_CLOSE:
begin
CloseSocket(TSocket(Msg.WParam ));
//删掉数组里的内容
end;
end;
end;
procedure TWsaServer.SendMsg(MyMsg: string);
var
I: Integer;
begin
i:=Send(CurrSocket,MyMsg,Length(MyMsg),0);
if i<> Length(MyMsg) then
raise Exception.Create('Send Msg Failed ');
end;
procedure TWsaServer.SetHost(const Value: string);
begin
FSockAddr.sin_addr.S_addr:=INET_ADDR(pchar(Value));
end;
procedure TWsaServer.SetPort(Value: Integer);
begin
FSockAddr.sin_port:=htons(Value);
end;
procedure TWsaServer.Start;
begin
FWorkFlag:=True;
end;
procedure TWsaServer.Stop;
begin
FWorkFlag:=False;
end;
procedure TWsaServer.WndProc(var Message: TMessage);
begin
try
Dispatch(Message);
except
if Assigned(ApplicationHandleException) then
ApplicationHandleException(Self);
end;
end;
procedure TWsaServer.WorkIt;
begin
FServerSocket:=Socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
if FServerSocket=INVALID_SOCKET then
raise Exception.Create('Socket Build Failed with error '+ inttostr(GetLastError()));
FSockAddr.sin_family :=PF_INET;
if bind(FServerSocket,FSockAddr,SizeOf(FSockAddr))<>0 then
raise Exception.Create('bind Failed with error'+ inttostr(GetLastError()));
Listen(FServerSocket,6);
WSAAsyncSelect(FServerSocket,Handle,WM_Server,FD_ACCEPT );
end;
end.
leaber
WSAASYNCSelect 简单易用,但是开发的时候需要相应的句柄来进行消息传递,
当然用FORM的句柄是最简便的,如果没有FORM如何解决:
1、增加一个HANDLE属性和相应的方法
2、为一个没有HANDLE的类加入消息处理功能,
3、增加一个消息分发的过程。
剩下就可以直接在类里面要处理消息的方法。
TSERVERSOCKET里面的实现就用到这种方式,记不太清了。
}
unit WsaServer;
interface
uses
SysUtils, Windows, Messages, Classes, Graphics, Controls,
Forms, Dialogs, Winsock;
const WM_Server = WM_USER + 5;
type
TSockets = array[1..64] of TSocket;
TConnectEvent = procedure (Sender: TObject) of object;
TReadEvent = procedure (Sender: TObject; Buffer: string;Skt:TSocket) of
object;
TWsaServer = class(TObject)
private
FCurrSocket: TSocket;
FHandle: THandle;
FNum: Integer;
FOnConnectEvent: TConnectEvent;
FOnReadEvent: TReadEvent;
FServerSocket: TSocket;
FSockAddr: TSockAddrIn;
FSockets: TSockets;
FWorkFlag: Boolean;
FWsaData: TWsaData;
function GetHandle: THandle;
function GetHost: string;
function GetPort: Integer;
function GetSockets(index:integer): TSocket;
procedure SetHost(const Value: string);
procedure SetPort(Value: Integer);
protected
procedure ProcessMsg(var Msg: TMessage); message WM_Server;
procedure WndProc(var Message: TMessage);
public
constructor Create;
destructor Destroy; override;
procedure SendMsg(MyMsg: string); virtual;
procedure Start; virtual;
procedure Stop; virtual;
procedure WorkIt; virtual;
property CurrSocket: TSocket read FCurrSocket;
property Handle: THandle read GetHandle;
property Host: string read GetHost write SetHost;
property Port: Integer read GetPort write SetPort;
property Sockets[index:integer]: TSocket read GetSockets;
published
property OnConnectEvent: TConnectEvent read FOnConnectEvent write
FOnConnectEvent;
property OnReadEvent: TReadEvent read FOnReadEvent write FOnReadEvent;
end;
implementation
{
********************************** TWsaServer **********************************
}
constructor TWsaServer.Create;
begin
if WSAStartUp($0202,FWsaData)<>0 then
Exception.Create('Init WINSOCK.DLL failed with'+ inttostr(WSAGetLastError()));
FNum:=0;
ZeroMemory(@FSockAddr,SizeOf(FSockAddr));
end;
destructor TWsaServer.Destroy;
begin
if FHandle <> 0 then
DeallocateHWnd(FHandle);
end;
function TWsaServer.GetHandle: THandle;
begin
if FHandle = 0 then
FHandle := AllocateHwnd(WndProc);
//这里实现了虚拟窗口,为以后的消息响应做准备
Result := FHandle;
end;
function TWsaServer.GetHost: string;
begin
Result:=inttostr(ntohs(FSockAddr.sin_addr.S_addr ));
end;
function TWsaServer.GetPort: Integer;
begin
Result:=ntohs(FSockAddr.sin_port);
end;
function TWsaServer.GetSockets(index:integer): TSocket;
begin
end;
procedure TWsaServer.ProcessMsg(var Msg: TMessage);
var
Event: Word;
Sa: TSockAddrin;
i: Integer;
Client: TSocket;
RecvBuffer: string;
begin
Event := Word(Msg.LParam);
case Event of
FD_ACCEPT:
begin
i:=SizeOf(Sa);
Client:=Accept(FServerSocket,@Sa,@i);
if Client=INVALID_SOCKET then
Exception.Create('Client Accept failed error with '+ inttostr(WSAGetLastError()));
WSAAsyncSelect(Client,Handle,WM_Server,FD_READ or FD_CLOSE);
FNum:=FNum+1;
FSockets[FNum]:=Client;
FCurrSocket:=Client;
end;
FD_READ:
begin
FCurrSocket:=TSocket(Msg.WParam );
SetLength(RecvBuffer,1024);
i:=Recv(FCurrSocket,RecvBuffer[1],1024,0);
if Assigned(OnReadEvent) then
OnReadEvent(nil,RecvBuffer,CurrSocket);
end;
FD_CLOSE:
begin
CloseSocket(TSocket(Msg.WParam ));
//删掉数组里的内容
end;
end;
end;
procedure TWsaServer.SendMsg(MyMsg: string);
var
I: Integer;
begin
i:=Send(CurrSocket,MyMsg,Length(MyMsg),0);
if i<> Length(MyMsg) then
raise Exception.Create('Send Msg Failed ');
end;
procedure TWsaServer.SetHost(const Value: string);
begin
FSockAddr.sin_addr.S_addr:=INET_ADDR(pchar(Value));
end;
procedure TWsaServer.SetPort(Value: Integer);
begin
FSockAddr.sin_port:=htons(Value);
end;
procedure TWsaServer.Start;
begin
FWorkFlag:=True;
end;
procedure TWsaServer.Stop;
begin
FWorkFlag:=False;
end;
procedure TWsaServer.WndProc(var Message: TMessage);
begin
try
Dispatch(Message);
except
if Assigned(ApplicationHandleException) then
ApplicationHandleException(Self);
end;
end;
procedure TWsaServer.WorkIt;
begin
FServerSocket:=Socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
if FServerSocket=INVALID_SOCKET then
raise Exception.Create('Socket Build Failed with error '+ inttostr(GetLastError()));
FSockAddr.sin_family :=PF_INET;
if bind(FServerSocket,FSockAddr,SizeOf(FSockAddr))<>0 then
raise Exception.Create('bind Failed with error'+ inttostr(GetLastError()));
Listen(FServerSocket,6);
WSAAsyncSelect(FServerSocket,Handle,WM_Server,FD_ACCEPT );
end;
end.