WSAAsyncSelect模型

WSAAsyncSelect模型允许应用程序以Windows消息的方式接收网络事件通知。许多对性能要求不高的网络应用程序都采用WSAAsyncSelect模型,MFC的CSocket类也使用了它。

WSAAsyncSelect自动把套接字设为非阻塞模式,并且为套接字绑定一个窗口句柄,当有网络事件发生时,便向这个窗口发送消息。

int WSAAsyncSelect(
       SOCKET s,        //需要设置的套接字句柄
       HWND  hWnd,      //指定一个窗口句柄, 套接字的通知消息将被发到此窗口中
       u_int    wMsg,   //网络事件到来的ID,可以在WM_USER以上数值中任意指定一个值
       long    IEvent   //指定哪些通知码需要发送
                        //FD_READ可以读套接字
                        //FD_WRITE 可以写套接字
                        //FD_ACCEPT 监听套接字有连接接入
                        //FD_CONNET  如果套接字连接对方主机,连接完成后会收到这个通知码
                        //FD_CLOSE 检测到套接字对应的连接被关闭
)

回传过来的消息类型与注册的wMsg相同,wParam等于套接字句柄,lParam通过WSAGETSELECTEVENT转义后就是FD_READ,FD_WRITE,FD_ACCEPT,FD_CONNET,FD_CLOSE
 

代码如下:

新建一个基于MFC对话框的工程,工程名为test,然后在testDlg.h中定义

#include "winsock2.h"
#pragma comment(lib, "WS2_32")
#define WM_SOCKET (WM_USER+1) 

同时在该文件中加入一个自定义消息处理函数

afx_msg LRESULT OnSocketMsg(WPARAM wParam,LPARAM lParam);

在testDlg.cpp中定义

ON_MESSAGE(WM_SOCKET,OnSocketMsg)

在OnInitDialog中加入自己的初始化代码

// TODO: 在此添加额外的初始化代码

	WSADATA wsaData;
	WORD sockVersion = MAKEWORD(2, 2);
	if(WSAStartup(sockVersion, &wsaData) != 0)
	{
		return 0;
	}
	USHORT nPort=4567;
	SOCKET s=socket(AF_INET,SOCK_STREAM,0);
	sockaddr_in sin;
	sin.sin_family=AF_INET;
	sin.sin_port=ntohs(nPort);
	sin.sin_addr.S_un.S_addr=INADDR_ANY;
	if(bind(s,(sockaddr*)&sin,sizeof(sin))==SOCKET_ERROR)
	{
		DWORD error=GetLastError();
		return TRUE;
	}

	WSAAsyncSelect(s,m_hWnd,WM_SOCKET,FD_ACCEPT|FD_CLOSE);
	listen(s,5);

添加自定义消息函数的处理:

LRESULT CtestDlg::OnSocketMsg(WPARAM wParam,LPARAM lParam)
{
	SOCKET s=wParam;
	CString strContent;
	if(WSAGETSELECTERROR(lParam))
	{
		closesocket(s);
		return false;
	}
	switch(WSAGETSELECTEVENT(lParam))
	{
	case FD_ACCEPT://检测到有套接字连上来
		{
			SOCKET client=accept(s,NULL,NULL);
			WSAAsyncSelect(client,m_hWnd,WM_SOCKET,FD_READ|FD_WRITE|FD_CLOSE);
			CString strContent;
			GetDlgItemText(IDC_EDIT1,strContent);
			if(!strContent.IsEmpty())
			{
				strContent+="\r\n";
			}			
			strContent+="有客户端连上来了";
			SetDlgItemText(IDC_EDIT1,strContent);//将内容显示到Edit控件
		}
		break;
	case FD_WRITE:
		{
		}
		break;
	case FD_READ:
		{
			char szText[1024]={0};
			if(recv(s,szText,1024,0)==-1)
				closesocket(s);
			else
			{				
				GetDlgItemText(IDC_EDIT1,strContent);
				if(!strContent.IsEmpty())
				{
					strContent+="\r\n";
				}
				CString strTemp;
				strTemp.Format("%s",szText);
				strContent+=strTemp;
				SetDlgItemText(IDC_EDIT1,strContent);//将内容显示到Edit控件中
			}
		}
		break;
	case FD_CLOSE:
		{
			closesocket(s);
			GetDlgItemText(IDC_EDIT1,strContent);
			if(!strContent.IsEmpty())
			{
				strContent+="\r\n";
			}			
			strContent+="有客户端断开了";
			SetDlgItemText(IDC_EDIT1,strContent);//将内容显示到Edit控件中
		}
		break;
	}
	return true;
}

对WM_DESTROY消息处理,清理套接字库

void CtestDlg::OnDestroy()
{
	CDialog::OnDestroy();
	WSACleanup();
	// TODO: 在此处添加消息处理程序代码
}

WSAAsyncSelect

分享到:
评论加载中,请稍后...
创APP如搭积木 - 创意无限,梦想即时!
回到顶部