WSAEventSelect类似于WSAAsycnSelect,区别就是当Socket上有“事件”时,传递一个Event而不是Windows消息。
1 unit Unit1; 2 3 interface 4 5 uses 6 WinSock2, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 7 Dialogs, StdCtrls, ExtCtrls; 8 9 type 10 TWorkThread = class(TThread) 11 private 12 FMemo: TMemo; 13 FBuff: array [0..10] of Char; 14 procedure ShowRecv; 15 protected 16 procedure Execute;override; 17 public 18 constructor Create(Memo: TMemo); 19 end; 20 21 TForm1 = class(TForm) 22 Memo1: TMemo; 23 procedure FormCreate(Sender: TObject); 24 private 25 { Private declarations } 26 public 27 { Public declarations } 28 end; 29 30 var 31 Form1: TForm1; 32 33 implementation 34 35 {$R *.dfm} 36 37 { TWorkThread } 38 39 constructor TWorkThread.Create(Memo: TMemo); 40 begin 41 inherited Create(False); 42 43 FMemo:= Memo; 44 end; 45 46 procedure TWorkThread.Execute; 47 var 48 WSData: TWSAData; 49 LocalAddr: TSockAddrIn; 50 ClientAddr: TSockAddrIn; 51 ClientAddrLen: Integer; 52 ServerSocket: TSocket; 53 ClientSocket: TSocket; 54 WSAEventObject: WSAEvent; 55 Idx: DWORD; 56 EventTotal: DWORD; 57 SocketArray: array [0..WSA_MAXIMUM_WAIT_EVENTS - 1] of TSocket; 58 WSAEventArray: array [0..WSA_MAXIMUM_WAIT_EVENTS - 1] of WSAEvent; 59 WSANetEvents: TWSANetworkEvents; 60 begin 61 inherited; 62 EventTotal:= 0; 63 FreeOnTerminate:= True; 64 65 //初始化Winsock 66 WSAStartUp($202, WSData); 67 //创建套接字 68 ServerSocket:= Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 69 //设置LocalAddr的参数 70 LocalAddr.sin_family:= AF_INET; //IPV4族 71 LocalAddr.sin_addr.S_addr:= INADDR_ANY;//这里不能写Inet_addr('127.0.0.1'),否则会绑定失败,不清楚原因是什么; 72 LocalAddr.sin_port:= Htons(1077); //Host To Net Short,主机字节顺序转为网络字节顺序 73 //绑定本机IP地址、端口,绑定之前先设置好LocalAddr的参数 74 Bind(ServerSocket, PSOCKADDR(@LocalAddr), SizeOf(LocalAddr)); 75 76 //创建EventObject 77 WSAEventObject:= WSACreateEvent(); 78 //使用WSAEventSelect模型 79 WSAEventSelect(ServerSocket, WSAEventObject, FD_ACCEPT or FD_READ or FD_CONNECT); 80 //开始监听,最多同时监听5个连接 81 Listen(ServerSocket, 5); 82 83 SocketArray[EventTotal]:= ServerSocket; 84 WSAEventArray[EventTotal]:= WSAEventObject; 85 Inc(EventTotal); 86 87 while not Terminated do 88 begin 89 //用WSAWaitForMultipleEvents检测是否有“事件”发生 90 Idx:= WSAWaitForMultipleEvents(EventTotal, @WSAEventArray[0], False, WSA_INFINITE, False); 91 //判断发生了什么“事件”——读、写、断开等等 92 WSAEnumNetWorkEvents(SocketArray[Idx - WSA_WAIT_EVENT_0], 93 WSAEventArray[Idx - WSA_WAIT_EVENT_0], @WSANetEvents); 94 95 if (WSANetEvents.lNetworkEvents and FD_ACCEPT) > 0 then //如果是Accept事件 96 begin 97 ClientAddrLen:= SizeOf(ClientAddr); 98 ClientSocket:= Accept(SocketArray[Idx - WSA_WAIT_EVENT_0], ClientAddr, ClientAddrLen); 99 100 WSAEventObject:= WSACreateEvent(); 101 WSAEventSelect(ClientSocket, WSAEventObject, FD_ACCEPT or FD_READ); 102 SocketArray[EventTotal]:= ClientSocket; 103 WSAEventArray[EventTotal]:= WSAEventObject; 104 Inc(EventTotal); 105 end; 106 107 if (WSANetEvents.lNetworkEvents and FD_READ) > 0 then //如果是Read事件 108 if Recv(SocketArray[Idx - WSA_WAIT_EVENT_0], FBuff, SizeOf(FBuff), 0) > 0 then 109 Synchronize(ShowRecv); 110 end; 111 end; 112 113 procedure TWorkThread.ShowRecv; 114 begin 115 FMemo.Lines.Add(FBuff); 116 end; 117 118 procedure TForm1.FormCreate(Sender: TObject); 119 begin 120 TWorkThread.Create(Memo1); 121 end; 122 123 end.
1.WSAEventSelect需要Winsock2.0,可以google搜索Winsock2.pas
2.使用Bind的时候要注意:LocalAddr.sin_addr.S_addr:= INADDR_ANY;//这里不能写Inet_addr('127.0.0.1'),否则会绑定失败,不清楚原因是什么