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; FClientSocket: TSocket; procedure ShowRecv; protected procedure Execute;override; public constructor Create(Memo: TMemo; ClientSocket: TSocket); end; TForm1 = class(TForm) Memo1: TMemo; Button1: TButton; Timer1: TTimer; procedure Timer1Timer(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; ServerSocket: TSocket; implementation {$R *.dfm} { TWorkThread } constructor TWorkThread.Create(Memo: TMemo; ClientSocket: TSocket); begin inherited Create(False); FMemo:= Memo; FClientSocket:= ClientSocket; end; procedure TWorkThread.Execute; var WSBuff: WSABuf; EventTotal: Integer; AcceptOverLapped: WSAOverLapped; WSAEventArray: array [0..WSA_MAXIMUM_WAIT_EVENTS - 1] of WSAEvent; Idx: Integer; ReceiveBytes: DWORD; Flags: DWORD; ByteTransferred: DWORD; begin inherited; FreeOnTerminate:= True; EventTotal:= 0; //创建事件 WSAEventArray[EventTotal]:= WSACreateEvent; //置零 ZeroMemory(@AcceptOverLapped, SizeOf(WSAOverLapped)); //关联事件 AcceptOverLapped.hEvent:= WSAEventArray[EventTotal]; WSBuff.len:= 22; //缓冲区的长度要大于客户端发送的长度,如果小于客户端发送长度,会出现乱码 WSBuff.buf:= FBuff; Inc(EventTotal); while not Terminated do begin //收消息 WSARecv(FClientSocket, @WSBuff, EventTotal, ReceiveBytes, Flags, @AcceptOverlapped, nil); //用WSAWaitForMultipleEvents检测是否有“事件”发生 Idx:= WSAWaitForMultipleEvents(EventTotal, @WSAEventArray[0], False, WSA_INFINITE, False); //用WSAGetOverlappedResult取得结果 WSAGetOverlappedResult(FClientSocket, @AcceptOverlapped, @ByteTransferred, False, Flags); //显示收到的内容 Synchronize(ShowRecv); //清零AcceptOverLapped ZeroMemory(@AcceptOverLapped, SizeOf(WSAOverLapped)); //关联事件 AcceptOverLapped.hEvent:= WSAEventArray[Idx - WSA_WAIT_EVENT_0]; //重置Event WSAResetEvent(WSAEventArray[Idx - WSA_WAIT_EVENT_0]); end; end; procedure TWorkThread.ShowRecv; begin FMemo.Lines.Add(FBuff); end; procedure TForm1.FormCreate(Sender: TObject); var WSData: TWSAData; LocalAddr: TSockaddr; SocketMode: Cardinal; begin //初始化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, @LocalAddr, SizeOf(LocalAddr)); SocketMode:= 1; IoCtlSocket(ServerSocket, FIONBIO, SocketMode); //开始监听 Listen(ServerSocket, 5); end; procedure TForm1.Timer1Timer(Sender: TObject); var ClientAddr: TSockAddr; ClientAddrLen: Integer; ClientSocket: TSocket; begin //接受客户端连接,为对应的客户端创建独立的线程 ClientAddrLen:= SizeOf(ClientAddr); ClientSocket:= Accept(ServerSocket, ClientAddr, ClientAddrLen); if ClientSocket <> INVALID_SOCKET then TWorkThread.Create(Memo1, ClientSocket); end; end.
1.此代码只是为了学习函数的使用方法,为了使代码简单,此处使用Timer管理客户端连接,并为每个连接创建独立的线程,Overlapped的处理方式可在线程的执行部分查看,实际应用中不应该用这种模式;
2.此代码为消息型的重叠(I/O Overlapped)模式,还有一种“完成例程”模式(非完成端口);