APIsocket,VS2010,windows非阻塞模式异步套接字编程(看孙鑫视频有感)

来源:互联网 发布:sd卡格式化后数据还在 编辑:程序博客网 时间:2024/06/11 21:34
作者在windows+vs2010写的,UDP,异步套接字。

windows socket有两种模式阻塞式和非阻塞式。

阻塞模式下,windows socket 会一直等待下去,线程会一直阻塞在这里。所以可以考虑使用多线程,创建线程,在线程中死循环,不断recvfrom(),然后PostMessage(),发送消息到消息队列,消息在主线程处理。(参考孙鑫老师Lesson15的Chat程序)

非阻塞模式下,可以利用WSAAsyncSelect()函数。WSAAsyncSelect(SOCKET s,HWND hWnd,usigned int wMsg,long lEvent)。参数lEvent指明应用程序感兴趣的网络事件的组合。该函数能够自动给窗口句柄发送消息(即参数mMsg),并自动将套接字设置为非阻塞模式。然后定义消息,在MESSAGE_MAP里把消息和消息响应函数函数关联起来,最后完成消息响应函数。(参考Lesson16)
写非阻塞模式程序时候发现问题。
1.VC6.0里可以将wMsg的消息响应函数返回值设置为void,但是在VS2010里面会报错error C2440: “static_cast”: 无法从“void (__thiscall CChatMessageDlg::* )(WPARAM,LPARAM)”转换为“LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)”。
为解决问题,在VS2010中将返回值设置为LRESULT。响应函数的参数lParam的低字节(用LOWORD(lParam)来取)里面保存了网络事件的类型。
2.采用WSA的socket的函数写以上程序的时候,出现了内存错误。作者插了断点,发现消息响应的WSARecvFrom没有接收到信息,准备接收信息的WSABUF变量仍然为空。
为解决问题,作者将有WSA前缀的socket函数换成socket函数(WSAAsyncSelect函数保留),运行OK。
下面附上代码:

1.初始化套接字函数

bool CChatMessageDlg::InitSocket(void){m_socket=socket(AF_INET,SOCK_DGRAM,0);//增加的扩展函数  与 socket()一样if ( INVALID_SOCKET ==m_socket){MessageBox("socket failed!");}SOCKADDR_IN addrSock;addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);addrSock.sin_family=AF_INET;addrSock.sin_port=htons(6000);if(SOCKET_ERROR==bind(m_socket,(sockaddr*)&addrSock,sizeof(sockaddr))){closesocket(m_socket);MessageBox("bind 失败");return false;}if (SOCKET_ERROR==WSAAsyncSelect(m_socket,m_hWnd,WM_SOCK,FD_READ)){MessageBox("注册网路读取事件 失败!");return false;}return true;}
该函数直接在OnInitDialog中调用即可。

2.Dialog.h头文件中define 消息

#define WM_SOCK WM_USER+1
3.Message_Map中

ON_MESSAGE(WM_SOCK,&CChatMessageDlg::OnSock)
4.消息响应函数

LRESULT CChatMessageDlg::OnSock(WPARAM wParam,LPARAM lParam){//MessageBox(" onsock");switch(LOWORD(lParam)){case FD_READ:{char recvbuf[200];char tempbuf[300];int retval;sockaddr_in addrfrom;int len=sizeof(addrfrom);retval=recvfrom(m_socket,recvbuf,200,0,(sockaddr*)&addrfrom,&len);if (SOCKET_ERROR==retval){return false;}CString str;CString strTemp;str.Format("%s说:%s",inet_ntoa(addrfrom.sin_addr),recvbuf);str+="\r\n";GetDlgItemText(IDC_EDIT_RECV,strTemp);//取出原有的消息str+=strTemp;SetDlgItemText(IDC_EDIT_RECV,str);break;}}return 0;}

5.响应发送按钮的函数

void CChatMessageDlg::OnBnClickedBtnSend(){//MessageBox("send ms");// TODO: 在此添加控件通知处理程序代码DWORD dwIP;//接收IP地址((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);SOCKADDR_IN addrTo;addrTo.sin_addr.S_un.S_addr=htonl(dwIP);//转化为网络字节序addrTo.sin_family=AF_INET;addrTo.sin_port=htons(6000);CString strSend;GetDlgItemText(IDC_EDIT_SEND,strSend);int len;len=strSend.GetLength()+1;sendto(m_socket,strSend,strSend.GetLength()+1,0,(sockaddr*)&addrTo,sizeof(addrTo));SetDlgItemText(IDC_EDIT_SEND,"");//清空 发送编辑框}

6.运行结果







原创粉丝点击