共有五种类型的套接字I/O模型,可让Winsock应用程序对I/O进行管理,它们包括: select(选择)、WSAAsyncSelect(异步选择)、WSAEventSelect(事件选择)、overlapped(重叠)以及 completion port(完成端口)。WSAAsyncSelect(异步选择)是最简单也最好理解的模式,因为用这个模式你都不需要明白多线程的编程知识~
话不多说,先上代码(下面的代码不包含异常处理,仅为学习使用):
1 //先在单元头部定义消息 2 const 3 WM_SOCKET = WM_USER + 55; 4 5 //然后定义处理消息的函数 6 procedure WMSocket(var Msg: TMessage); message WM_SOCKET; 7 8 procedure TForm1.FormCreate(Sender: TObject); 9 var 10 WSData: WSAData; 11 ServerSocket: TSocket; 12 LocalAddr: TSockAddrIn; 13 begin 14 //初始化Winsock 15 WSAStartUp($202, WSData); 16 //创建套接字 17 ServerSocket:= Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 18 19 //设置LocalAddr的参数 20 LocalAddr.sin_family:= AF_INET; //IPV4族 21 LocalAddr.sin_addr.S_addr:= Inet_addr('127.0.0.1');//点分字符串格式的IP地址转换为互联网格式 22 LocalAddr.sin_port:= Htons(1077); //Host To Net Short,主机字节顺序转为网络字节顺序 23 //绑定本机IP地址、端口,绑定之前先设置好LocalAddr的参数 24 Bind(ServerSocket, LocalAddr, SizeOf(LocalAddr)); 25 26 //设置WinSock I/O模式 27 WSAAsyncSelect(ServerSocket, Handle, WM_SOCKET, FD_ACCEPT or FD_READ); 28 29 //开始监听,最多同时监听5个连接 30 Listen(ServerSocket, 5); 31 end; 32 33 procedure TForm1.WMSocket(var Msg: TMessage); 34 var 35 Buff: array [0 .. 10] of Char; 36 AddrIn: TSockAddrIn; 37 AddrLen: Integer; 38 ClientSocket: TSocket; 39 begin 40 case WSAGetSelectEvent(Msg.LParam) of 41 FD_ACCEPT: //收到连接请求 42 begin 43 AddrLen := SizeOf(AddrIn); 44 ClientSocket := Accept(Msg.WParam, @AddrIn, @AddrLen); 45 46 WSAAsyncSelect(ClientSocket, Handle, WM_SOCKET, FD_ACCEPT or FD_READ); 47 end; 48 FD_READ: //有消息从客户端发过来的时候 49 begin 50 Recv(Msg.WParam, Buff, SizeOf(Buff), 0); 51 Memo1.Lines.Add(Buff); 52 Buff := 'I Received!'; 53 Send(Msg.WParam, Buff, SizeOf(Buff), 0); 54 end; 55 end; 56 end;
关于WSAAsyncSelect的一些说明:
1.如果用这种模式,你的程序必须要有一个Windows窗体
2.首先你要自己定义一个消息,当连接上有“动作”(看你在WSAAsyncSelect时设置了哪些动作)时,你的窗体就会收到这个消息
3.Msg.WParam表明了是哪个连接,Msg.LParam表明了是什么“动作”(读、写、关闭、连接等等)
4.WSAAsyncSelect的第四个参数表明了它可以监视哪些动作,常用的有FD_Accept, FD_Read, FD_Write, FD_Close