WSAAsyncSelect模型是winsock编程模型的一种,它提供了socket异步编程的方便,其实现是基于Windows消息机制的,最主要的就是下面这个函数:
1 int PASCAL FAR WSAAsyncSelect (SOCKET s,HWND hWnd,unsigned int wMsg,long lEvent);
s 标识一个需要事件通知的套接口的描述符.
hWnd 标识一个在网络事件发生时需要接收消息的窗口句柄.
wMsg 在网络事件发生时要接收的消息.
lEvent位屏蔽码,用于指明应用程序感兴趣的网络事件集合.
1、服务器端
因此首先需要自定义一个消息
#define WM_SOCKET WM_USER + 1
并定义消息处理函数,以及做映射
1 // 声明消息处理函数 2 afx_msg LRESULT OnSocket(WPARAM wParam, LPARAM lParam); 3 // 映射 4 ON_MESSAGE(WM_SOCKET,OnSocket)
初始化socket
1 BOOL CSocketSeverDlg::InitNetwork() 2 { 3 WSADATA wsaData; 4 //初始化TCP协议 5 BOOL ret = WSAStartup(MAKEWORD(2,2), &wsaData); 6 if(ret != 0) 7 { 8 MessageBox("初始化网络协议失败!"); 9 return FALSE; 10 } 11 //创建服务器端套接字 12 ServerSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 13 if(ServerSock == INVALID_SOCKET) 14 { 15 MessageBox("创建套接字失败!"); 16 closesocket(ServerSock); 17 WSACleanup(); 18 return FALSE; 19 } 20 //绑定到本地一个端口上 21 sockaddr_in localaddr; 22 localaddr.sin_family = AF_INET; 23 localaddr.sin_port = htons(8888); file://端口号不要与其他应用程序冲突 24 localaddr.sin_addr.s_addr = 0; 25 if(SOCKET_ERROR = = bind(ServerSock ,(struct sockaddr*)&localaddr,sizeof(sockaddr))) 26 { 27 MessageBox("绑定地址失败!"); 28 closesocket(ServerSock); 29 WSACleanup(); 30 return FALSE; 31 } 32 //将SeverSock设置为异步非阻塞模式,并为它注册各种网络异步事件,其 中 m_hWnd 33 //为应用程序的主对话框或主窗口的句柄 34 if(SOCKET_ERROR == WSAAsyncSelect(ServerSock, m_hWnd, WM_SOCKET, 35 FD_ACCEPT | FD_CLOSE | FD_READ | FD_WRITE)) 36 { 37 MessageBox("注册网络异步事件失败!"); 38 WSACleanup(); 39 return FALSE; 40 } 41 //设置侦听模式 42 listen(ServerSock, 5); 43 return TRUE; 44 }
定义自定义消息处理函数
1 LRESULT CSocketSeverDlg::OnSocket(WPARAM wParam, LPARAM lParam) 2 { 3 //调用Winsock API函数,得到网络事件类型 4 int iEvent = WSAGETSELECTEVENT(lParam); 5 //调用Winsock API函数,得到发生此事件的客户端套接字 6 SOCKET CurSock= (SOCKET)wParam; 7 switch(iEvent) 8 { 9 case FD_ACCEPT: 10 //客户端连接请求事件 11 OnAccept(CurSock); 12 break; 13 case FD_CLOSE: 14 //客户端断开事件: 15 OnClose(CurSock); 16 break; 17 case FD_READ: 18 //网络数据包到达事件 19 OnReceive(CurSock); 20 break; 21 case FD_WRITE: 22 //发送网络数据事件 23 OnSend(CurSock); 24 break; 25 default: break; 26 } 27 return 0; 28 }
2、客户端
用同样的方法建立一个客户端应用程序,初始化网络部分,不需要将套接字设置为监听模式。注册网络事件时没有FD_ACCEPT,但增加了FD_CONNECT事件,因此没有OnAccept函数,但增加了OnConnect函数,向服务器发出连接请求时,使用connect函数,连接成功后,会相应到OnConnect函数中。下面是OnConnect函数的定义,传进来的参数是客户端Socket和服务器端发回来的连接是否成功的标识。
1 void CSocketClientDlg::OnConnect(SOCKET CurSock, int error) 2 { 3 if(0 == error) 4 { 5 if(CurSock == ClientSock) 6 { 7 MessageBox("连接成功!"); 8 } 9 } 10 }
定义OnReceive函数,处理网络数据到达事件
定义OnSend函数,处理发送网络数据事件
定义OnClose函数,处理服务器socket关闭事件
以上就是用基于windows消息机制的异步I/O模型实现服务器/客户端应用程序的基本方法。
3、我的疑问
我有一点不是很明白,那就是这个发送网络数据事件是什么意思?什么时候发生?是我们使用send函数发送数据时发生么,
未完待续。。。