WinSock学习笔记4:WSAEventSelect模型
WSAEventSelect类似于WSAAsycnSelect,区别就是当Socket上有“事件”时,传递一个Event而不是Windows消息。
unit Unit1;
interface
uses
WinSock2, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TWorkThread = class (TThread)
private
FMemo: TMemo;
FBuff: array [ 0 .. 10 ] of Char;
procedure ShowRecv;
protected
procedure Execute; override ;
public
constructor Create(Memo: TMemo);
end;
TForm1 = class (TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R * .dfm}
{ TWorkThread }
constructor TWorkThread.Create(Memo: TMemo);
begin
inherited Create(False);
FMemo: = Memo;
end;
procedure TWorkThread.Execute;
var
WSData: TWSAData;
LocalAddr: TSockAddrIn;
ClientAddr: TSockAddrIn;
ClientAddrLen: Integer;
ServerSocket: TSocket;
ClientSocket: TSocket;
WSAEventObject: WSAEvent;
Idx: DWORD;
EventTotal: DWORD;
SocketArray: array [ 0 ..WSA_MAXIMUM_WAIT_EVENTS - 1 ] of TSocket;
WSAEventArray: array [ 0 ..WSA_MAXIMUM_WAIT_EVENTS - 1 ] of WSAEvent;
WSANetEvents: TWSANetworkEvents;
begin
inherited;
EventTotal: = 0 ;
FreeOnTerminate: = True;
// 初始化Winsock
WSAStartUp($ 202 , WSData);
// 创建套接字
ServerSocket: = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// 设置LocalAddr的参数
LocalAddr.sin_family: = AF_INET; // IPV4族
LocalAddr.sin_addr.S_addr: = INADDR_ANY; // 这里不能写Inet_addr('127.0.0.1'),否则会绑定失败,不清楚原因是什么;
LocalAddr.sin_port: = Htons( 1077 ); // Host To Net Short,主机字节顺序转为网络字节顺序
// 绑定本机IP地址、端口,绑定之前先设置好LocalAddr的参数
Bind(ServerSocket, PSOCKADDR(@LocalAddr), SizeOf(LocalAddr));
// 创建EventObject
WSAEventObject: = WSACreateEvent();
// 使用WSAEventSelect模型
WSAEventSelect(ServerSocket, WSAEventObject, FD_ACCEPT or FD_READ or FD_CONNECT);
// 开始监听,最多同时监听5个连接
Listen(ServerSocket, 5 );
SocketArray[EventTotal]: = ServerSocket;
WSAEventArray[EventTotal]: = WSAEventObject;
Inc(EventTotal);
while not Terminated do
begin
// 用WSAWaitForMultipleEvents检测是否有“事件”发生
Idx: = WSAWaitForMultipleEvents(EventTotal, @WSAEventArray[ 0 ], False, WSA_INFINITE, False);
// 判断发生了什么“事件”——读、写、断开等等
WSAEnumNetWorkEvents(SocketArray[Idx - WSA_WAIT_EVENT_0],
WSAEventArray[Idx - WSA_WAIT_EVENT_0], @WSANetEvents);
if (WSANetEvents.lNetworkEvents and FD_ACCEPT) > 0 then // 如果是Accept事件
begin
ClientAddrLen: = SizeOf(ClientAddr);
ClientSocket: = Accept(SocketArray[Idx - WSA_WAIT_EVENT_0], ClientAddr, ClientAddrLen);
WSAEventObject: = WSACreateEvent();
WSAEventSelect(ClientSocket, WSAEventObject, FD_ACCEPT or FD_READ);
SocketArray[EventTotal]: = ClientSocket;
WSAEventArray[EventTotal]: = WSAEventObject;
Inc(EventTotal);
end;
if (WSANetEvents.lNetworkEvents and FD_READ) > 0 then // 如果是Read事件
if Recv(SocketArray[Idx - WSA_WAIT_EVENT_0], FBuff, SizeOf(FBuff), 0 ) > 0 then
Synchronize(ShowRecv);
end;
end;
procedure TWorkThread.ShowRecv;
begin
FMemo.Lines.Add(FBuff);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
TWorkThread.Create(Memo1);
end;
end.
interface
uses
WinSock2, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TWorkThread = class (TThread)
private
FMemo: TMemo;
FBuff: array [ 0 .. 10 ] of Char;
procedure ShowRecv;
protected
procedure Execute; override ;
public
constructor Create(Memo: TMemo);
end;
TForm1 = class (TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R * .dfm}
{ TWorkThread }
constructor TWorkThread.Create(Memo: TMemo);
begin
inherited Create(False);
FMemo: = Memo;
end;
procedure TWorkThread.Execute;
var
WSData: TWSAData;
LocalAddr: TSockAddrIn;
ClientAddr: TSockAddrIn;
ClientAddrLen: Integer;
ServerSocket: TSocket;
ClientSocket: TSocket;
WSAEventObject: WSAEvent;
Idx: DWORD;
EventTotal: DWORD;
SocketArray: array [ 0 ..WSA_MAXIMUM_WAIT_EVENTS - 1 ] of TSocket;
WSAEventArray: array [ 0 ..WSA_MAXIMUM_WAIT_EVENTS - 1 ] of WSAEvent;
WSANetEvents: TWSANetworkEvents;
begin
inherited;
EventTotal: = 0 ;
FreeOnTerminate: = True;
// 初始化Winsock
WSAStartUp($ 202 , WSData);
// 创建套接字
ServerSocket: = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// 设置LocalAddr的参数
LocalAddr.sin_family: = AF_INET; // IPV4族
LocalAddr.sin_addr.S_addr: = INADDR_ANY; // 这里不能写Inet_addr('127.0.0.1'),否则会绑定失败,不清楚原因是什么;
LocalAddr.sin_port: = Htons( 1077 ); // Host To Net Short,主机字节顺序转为网络字节顺序
// 绑定本机IP地址、端口,绑定之前先设置好LocalAddr的参数
Bind(ServerSocket, PSOCKADDR(@LocalAddr), SizeOf(LocalAddr));
// 创建EventObject
WSAEventObject: = WSACreateEvent();
// 使用WSAEventSelect模型
WSAEventSelect(ServerSocket, WSAEventObject, FD_ACCEPT or FD_READ or FD_CONNECT);
// 开始监听,最多同时监听5个连接
Listen(ServerSocket, 5 );
SocketArray[EventTotal]: = ServerSocket;
WSAEventArray[EventTotal]: = WSAEventObject;
Inc(EventTotal);
while not Terminated do
begin
// 用WSAWaitForMultipleEvents检测是否有“事件”发生
Idx: = WSAWaitForMultipleEvents(EventTotal, @WSAEventArray[ 0 ], False, WSA_INFINITE, False);
// 判断发生了什么“事件”——读、写、断开等等
WSAEnumNetWorkEvents(SocketArray[Idx - WSA_WAIT_EVENT_0],
WSAEventArray[Idx - WSA_WAIT_EVENT_0], @WSANetEvents);
if (WSANetEvents.lNetworkEvents and FD_ACCEPT) > 0 then // 如果是Accept事件
begin
ClientAddrLen: = SizeOf(ClientAddr);
ClientSocket: = Accept(SocketArray[Idx - WSA_WAIT_EVENT_0], ClientAddr, ClientAddrLen);
WSAEventObject: = WSACreateEvent();
WSAEventSelect(ClientSocket, WSAEventObject, FD_ACCEPT or FD_READ);
SocketArray[EventTotal]: = ClientSocket;
WSAEventArray[EventTotal]: = WSAEventObject;
Inc(EventTotal);
end;
if (WSANetEvents.lNetworkEvents and FD_READ) > 0 then // 如果是Read事件
if Recv(SocketArray[Idx - WSA_WAIT_EVENT_0], FBuff, SizeOf(FBuff), 0 ) > 0 then
Synchronize(ShowRecv);
end;
end;
procedure TWorkThread.ShowRecv;
begin
FMemo.Lines.Add(FBuff);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
TWorkThread.Create(Memo1);
end;
end.
1.WSAEventSelect需要Winsock2.0,可以google搜索Winsock2.pas;
2.使用Bind的时候要注意:LocalAddr.sin_addr.S_addr:= INADDR_ANY;//这里不能写Inet_addr('127.0.0.1'),负责会绑定失败,不清楚原因是什么;
原文: http://blog.csdn.net/dropme/archive/2009/09/10/4538553.aspx