网络编程(53)—— Windows下使用WSAAsyncSelect实现窗口处理socket消息
来源:互联网 发布:怎么做网络宣传 编辑:程序博客网 时间:2024/06/13 14:13
一、引言
上一文中我们介绍了使用WSAEventSelect实现异步通知IO的方法,本文我们主要讨论下使用WSAAsyncSelect处理socket的方法。本文的主要目标,是创建一个带界面的回声服务端,接收并返回客户端传过来的字符串,并在界面上显示该字符串。为此,我们将采用MFC的编程环境,建立如下的对话框程序:
二、WSAAsyncSelect函数
WSAAsyncSelect也是windows下一种异步的select,它可以注册IO事件,当发生注册的IO事件时,它会发送一个我们自定义的消息给我们的窗口,而我们在窗口的消息处理函数中就可以处理这些消息了。它的原型如下:
int WSAAsyncSelect( __in SOCKET s, __in HWND hWnd, __in unsigned int wMsg, __in long lEvent);
s —— 用于监视的socket。
hWnd —— 用来接收socket消息的窗口。
wMsg —— 是我们自定义的消息,一般情况下使用“WM_USER+ 数字”的形式进行定义。
lEvent —— 进行监视的IO事件,包含如下几种:
FD_READ:套接字可读通知。
FD_WRITE:可写通知。
FD_ACCEPT:服务器接收连接的通知。
FD_CONNECT:有客户连接通知。
FD_OOB:外带数据到达通知。
FD_CLOSE:套接字关闭通知。
FD_QOS:服务质量发生变化通知。
FD_GROUP_QOS:组服务质量发生变化通知。
FD_ROUTING_INTERFACE_CHANGE:与路由器接口发生变化的通知。
FD_ADDRESS_LIST_CHANGE:本地地址列表发生变化的通知。
返回值 —— 正常情况下返回0,出现错误时返回错误码。
我们知道Windows系统中消息都会携带两个参数wParam和lParam,我们在进行窗口的消息处理时往往会利用这两个参数。WSAAsyncSelect发送的socket消息也不例外,它的wParam参数携带的是发生IO事件的socket。而lParam低字节表明已发生的事件。高字节包含错误代码。我们可以使用WSAGETSElECTERROR宏来读取lParam的高字节获取错误码,使用WSAGETSELECTEVENT宏读取lParam的低字节来获取发生的事件类型。
三、编程步骤
3.1 自定义消息
我们先自定义一个socket消息以用WSAAsyncSelect发送:
#define WM_SOCKET WM_USER+1
3.2 注册服务端的socket
我们先经过一般步骤创建服务端的socket,并然后用WSAAsyncSelect进行注册:
WSAStartup(MAKEWORD(2,2),&m_wsaData); m_servSock=socket(AF_INET,SOCK_STREAM,0); memset(&m_servAddr,0,sizeof(m_servAddr)); m_servAddr.sin_family=AF_INET; m_servAddr.sin_addr.s_addr=htonl(INADDR_ANY); m_servAddr.sin_port=htons(atoi("8888")); bind(m_servSock,(SOCKADDR*)&m_servAddr,sizeof(m_servAddr)); listen(m_servSock,5); WSAAsyncSelect(m_servSock,this->m_hWnd,WM_SOCKET,FD_ACCEPT|FD_READ);
最后一句代码中,我们使用WSAAsyncSelect注册了服务端的socketm_servSock,WSAAsyncSelect的第二个参数填写了我们窗口的m_hWnd值,第三个参数是我们自定义的消息,而第四个参数填写的是注册的IO事件,分别表示接受链接和有数据可读。注册完成之后,一旦有新的客户端连接,系统就会发送一个WM_SOCKET消息给我们的窗口。
3.3 处理socket消息
为了能够处理socket消息,我们先引入窗口的消息处理函数,从类向导中添加虚函数OnWndMsg,在OnWndMsg中我们进行socket消息的处理:
BOOL CWSAAsyncSelectServDlg::OnWndMsg(UINT message,WPARAM wParam, LPARAM lParam, LRESULT* pResult){ switch(message) { case WM_SOCKET: { SOCKETsock = (SOCKET) wParam; if(m_servSock == sock) { //获?取¨? m_clntAddrSz=sizeof(m_clntAddr); m_clntSock=accept(m_servSock,(SOCKADDR*)&m_clntAddr,&m_clntAddrSz); WSAAsyncSelect(m_clntSock,this->m_hWnd,WM_SOCKET,FD_READ); //将?m_clntSock和¨ªm_clntAddr存ä?到Ì?映®3射¦?中D m_sockMap.SetAt(m_clntSock,m_clntAddr); PrintClientConnectMsg(); } else { m_strLen= recv(sock,buf,BUF_SIZE - 1,0); send(sock,buf,m_strLen,0); buf[m_strLen]=0; PrintClientSendMsg(sock); } } break; default: break; } return CDialogEx::OnWndMsg(message, wParam, lParam,pResult);}从上述函数的WM_SOCKETswitch分支可以看到,我们通过wParam获取到了发生IO事件的socket,如果有需要还可以通过lParam获取到错误码或者事件类型。获取到socket之后,先判断socket是不是服务端的m_servSock。如果是,表明有新的客户端链接,接收连接并打印客户端信息;如果不是则是由客户端传来了数据,调用recv接收数据并send给客户端,最后打印数据。
下面是用来打印客户端信息和客户端数据的两个函数:
void CWSAAsyncSelectServDlg::PrintClientConnectMsg(void){ CString str; CTimelocTime=CTime::GetCurrentTime(); //获?取¨?当Ì¡À前¡ã时º¡À间? CStringstrTime=locTime.Format("%Y-%m-%d%H:%M:%S");//将?当Ì¡À前¡ã时º¡À间?转Áa换?成¨¦CString类¤¨¤型¨ª str.Format("%s Client %s:%d Connectted",strTime,inet_ntoa(m_clntAddr.sin_addr),m_clntAddr.sin_port); this->m_list.AddString(str);} void CWSAAsyncSelectServDlg::PrintClientSendMsg(SOCKET sock){ CString str; m_clntAddr=m_sockMap[sock]; CTimelocTime=CTime::GetCurrentTime(); CStringstrTime=locTime.Format("%Y-%m-%d%H:%M:%S");//将?当Ì¡À前¡ã时º¡À间?转Áa换?成¨¦CString类¤¨¤型¨ª str.Format("%s Client %s:%d say:%s",strTime,inet_ntoa(m_clntAddr.sin_addr),m_clntAddr.sin_port,buf); this->m_list.AddString(str);}
运行程序,效果如下,服务端不单返回了客户端传过来的信息,还对信息进行了打印。
客户端1:
客户端2:
服务端:
Github位置:
https://github.com/HymanLiuTS/NetDevelopment
克隆本项目:
git clone git@github.com:HymanLiuTS/NetDevelopment.git
获取本文源代码:
git checkout NL53
- 网络编程(53)—— Windows下使用WSAAsyncSelect实现窗口处理socket消息
- windows下网络编程(一)——SDK socket
- 网络编程(56)—— Windows下使用IOCP构建socket服务端
- Socket网络编程之WSAAsyncSelect模型
- Socket编程 消息传送 TCP协议(窗口实现) 客户端
- Socket编程 消息传送 TCP协议(窗口实现) 服务器
- Socket编程 消息传送 UDP协议(窗口实现) 服务器
- Socket编程 消息传送 UDP协议(窗口实现) 客户端
- 网络编程(52)—— Windows下使用WSAEventSelect实现异步通知IO
- WSAAsyncSelect消息编程
- Winsock 网络编程 Socket模型之WSAAsyncSelect模型
- Windows Socket编程TCP范例之三(WSAAsyncSelect)
- 黑马程序员——网络编程(Socket编程)下
- WIN网络编程-WSAAsyncSelect
- 网络编程UDP的socket编程实现(linux下)
- WINDOWS SOCKET下的网络编程
- windows下socket 网络通信编程二
- windows下socket网络编程小节
- Android自定义View(CustomCalendar-定制日历控件)
- NIPS 2016上22篇论文的实现汇集
- Climbing Stairs
- poj 2229 (动态规划,找规律)
- jmx相关资料
- 网络编程(53)—— Windows下使用WSAAsyncSelect实现窗口处理socket消息
- RSA攻击----已知公钥n,e私钥d
- epoll详细工作原理
- 【LeetCode】 406. Queue Reconstruction by Height
- 音频和语音处理领域CCF期刊和杂志
- 计算几何 学习笔记
- #<center> Java 语言线程
- Mysql分区
- VC++数据类型转换大全