WSAAsyncSelect 模型

时间:2021-08-08 15:47:08

WSAAsyncSelect模型是winsock编程模型的一种,它提供了socket异步编程的方便,其实现是基于Windows消息机制的,最主要的就是下面这个函数:

 int PASCAL FAR WSAAsyncSelect (SOCKET s,HWND hWnd,unsigned int wMsg,long lEvent);

s 标识一个需要事件通知的套接口的描述符.
hWnd 标识一个在网络事件发生时需要接收消息的窗口句柄.
wMsg 在网络事件发生时要接收的消息.
lEvent位屏蔽码,用于指明应用程序感兴趣的网络事件集合.

1、服务器端

因此首先需要自定义一个消息

#define WM_SOCKET WM_USER + 1

并定义消息处理函数,以及做映射

 // 声明消息处理函数
afx_msg LRESULT OnSocket(WPARAM wParam, LPARAM lParam);
// 映射
ON_MESSAGE(WM_SOCKET,OnSocket)

初始化socket

 BOOL CSocketSeverDlg::InitNetwork()
{
WSADATA wsaData;
//初始化TCP协议
BOOL ret = WSAStartup(MAKEWORD(,), &wsaData);
if(ret != )
{
MessageBox("初始化网络协议失败!");
return FALSE;
}
//创建服务器端套接字
ServerSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(ServerSock == INVALID_SOCKET)
{
MessageBox("创建套接字失败!");
closesocket(ServerSock);
WSACleanup();
return FALSE;
}
//绑定到本地一个端口上
sockaddr_in localaddr;
localaddr.sin_family = AF_INET;
localaddr.sin_port = htons(); file://端口号不要与其他应用程序冲突
localaddr.sin_addr.s_addr = ;
if(SOCKET_ERROR = = bind(ServerSock ,(struct sockaddr*)&localaddr,sizeof(sockaddr)))
{
MessageBox("绑定地址失败!");
closesocket(ServerSock);
WSACleanup();
return FALSE;
}
//将SeverSock设置为异步非阻塞模式,并为它注册各种网络异步事件,其 中 m_hWnd
//为应用程序的主对话框或主窗口的句柄
if(SOCKET_ERROR == WSAAsyncSelect(ServerSock, m_hWnd, WM_SOCKET,
FD_ACCEPT | FD_CLOSE | FD_READ | FD_WRITE))
{
MessageBox("注册网络异步事件失败!");
WSACleanup();
return FALSE;
}
//设置侦听模式
listen(ServerSock, );
return TRUE;
}

定义自定义消息处理函数

 LRESULT CSocketSeverDlg::OnSocket(WPARAM wParam, LPARAM lParam)
{
//调用Winsock API函数,得到网络事件类型
int iEvent = WSAGETSELECTEVENT(lParam);
//调用Winsock API函数,得到发生此事件的客户端套接字
SOCKET CurSock= (SOCKET)wParam;
switch(iEvent)
{
case FD_ACCEPT:
//客户端连接请求事件
OnAccept(CurSock);
break;
case FD_CLOSE:
//客户端断开事件:
OnClose(CurSock);
break;
case FD_READ:
//网络数据包到达事件
OnReceive(CurSock);
break;
case FD_WRITE:
//发送网络数据事件
OnSend(CurSock);
break;
default: break;
}
return ;
}

2、客户端

用同样的方法建立一个客户端应用程序,初始化网络部分,不需要将套接字设置为监听模式。注册网络事件时没有FD_ACCEPT,但增加了FD_CONNECT事件,因此没有OnAccept函数,但增加了OnConnect函数,向服务器发出连接请求时,使用connect函数,连接成功后,会相应到OnConnect函数中。下面是OnConnect函数的定义,传进来的参数是客户端Socket和服务器端发回来的连接是否成功的标识。

 void CSocketClientDlg::OnConnect(SOCKET CurSock, int error)
{
if( == error)
{
if(CurSock == ClientSock)
{
MessageBox("连接成功!");
}
}
}

定义OnReceive函数,处理网络数据到达事件

定义OnSend函数,处理发送网络数据事件

定义OnClose函数,处理服务器socket关闭事件

以上就是用基于windows消息机制的异步I/O模型实现服务器/客户端应用程序的基本方法。

3、我的疑问

我有一点不是很明白,那就是这个发送网络数据事件是什么意思?什么时候发生?是我们使用send函数发送数据时发生么,

未完待续。。。