套接字I/O模型-WSAAsyncSelect
2012-03-09 14:32
357 查看
利用这个异步I/O模型,应用程序可在一个套接字上接收以Windows消息为基础的网络事件通知。WSAAsyncSelect和WSAEventSelect提供读写数据能力的异步通知,但它们不提供异步数据传输,重叠及完成端口提供异步数据传输。
消息通知
要想使用WSAAsyncSelect模型,在应用程序中,首先必须用CreateWindow函数创建一个窗口,再为该窗口提供一个窗口过程支持函数,亦可使用一个对话框,为其提供一个对话框过程来代替窗口过程,这是因为对话框本质也是窗口。
大多数应用程序感兴趣的网络事件类型包括:FD_READ,FD_WRITE,FD_ACCEPT,FD_CONNECT,FD_CLOSE
WSAAsyncSelect(s, hwnd, WM_SOCKET, FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE);
这样应用程序可在套接字s上接收到有关连接发送接收以及关闭套接字这一网络事件的通知。特别注意的是对各网络事件务必在套接字上一次完成注册。一旦某个套接字上启用了事件通知,那么以后除非明确调用closesocket,或者由应用程序针对这个套接字调用WSAAsyncSelect,从而更改注册的网络事件类型,否则网络事件总是有效。若将lEvent设为0,则效果相当于停止在套接字上进行的所有网络事件通知。
若应用程序针对一个套接字调用WSAsyncSelect,那么套接字的模式会从阻塞模式自动转换为非阻塞模式。
演示WSAAsyncSelect程序基本流程:
最后一个特别有价值的问题是应用程序如何对FD_WRITE事件通知进行处理,只有3种条件下,FD_WRITE通知才会发出:
1.使用connect或WSAConnect,一个套接字首次建立连接
2.使用accept或WSAAccept,套接字被接受以后
3.若send,WSASend,sendto或WSASendTo操作失败,返回了WSAEWOULDBLOCK错误,而且缓冲区的空间变得可用时
优点是它可以在系统开销不大的情况下同时处理许多连接,而select需要建立fd_set结构。
缺点是即使应用程序不需要窗口,它也不得不额外使用一个窗口。同时,用一个单窗口程序来处理成千上万的套接字中的所有事件,很可能成为性能瓶颈。
========================================================================
服务器端得主要流程:
1.在WM_CREATE消息处理函数中,初始化Windows Socket library,创建监听套接字,绑定,监听,并且调用WSAAsyncSelect函数表示我们关心在监听套接字上发生的FD_ACCEPT事件;
2.自定义一个消息WM_SOCKET,一旦在我们所关心的套接字(监听套接字和客户端套接字)上发生了某个事件,系统就会调用WndProc并且message参数被设置为WM_SOCKET;
3.在WM_SOCKET的消息处理函数中,分别对FD_ACCEPT、FD_READ和FD_CLOSE事件进行处理;
4.在窗口销毁消息(WM_DESTROY)的处理函数中,我们关闭监听套接字,清除Windows Socket library
WSAAsyncSelect函数的网络事件类型可以有以下一种:
FD_READ 应用程序想要接收有关是否可读的通知,以便读入数据
FD_WRITE 应用程序想要接收有关是否可写的通知,以便写入数据
FD_OOB 应用程序想接收是否有带外(OOB)数据抵达的通知
FD_ACCEPT 应用程序想接收与进入连接有关的通知
FD_CONNECT 应用程序想接收与一次连接或者多点join操作完成的通知
FD_CLOSE 应用程序想接收与套接字关闭有关的通知
FD_QOS 应用程序想接收套接字“服务质量”(QoS)发生更改的通知
FD_GROUP_QOS 应用程序想接收套接字组“服务质量”发生更改的通知(现在没什么用处,为未来套接字组的使用保留)
FD_ROUTING_INTERFACE_CHANGE 应用程序想接收在指定的方向上,与路由接口发生变化的通知
FD_ADDRESS_LIST_CHANGE 应用程序想接收针对套接字的协议家族,本地地址列表发生变化的通知
消息通知
要想使用WSAAsyncSelect模型,在应用程序中,首先必须用CreateWindow函数创建一个窗口,再为该窗口提供一个窗口过程支持函数,亦可使用一个对话框,为其提供一个对话框过程来代替窗口过程,这是因为对话框本质也是窗口。
int WSAAsyncSelect( SOCKET s,//我们感兴趣的套接字 HWND hwnd,//窗口句柄,标识的是网络事件发生之后,想要收到通知消息的那个窗口或对话框 unsigned int wMsg,//在发生网络事件时,打算接收的消息,该消息将被投递到由hwnd窗口句柄所标识的那个窗口 long lEvent//网络事件组合 );
大多数应用程序感兴趣的网络事件类型包括:FD_READ,FD_WRITE,FD_ACCEPT,FD_CONNECT,FD_CLOSE
WSAAsyncSelect(s, hwnd, WM_SOCKET, FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE);
这样应用程序可在套接字s上接收到有关连接发送接收以及关闭套接字这一网络事件的通知。特别注意的是对各网络事件务必在套接字上一次完成注册。一旦某个套接字上启用了事件通知,那么以后除非明确调用closesocket,或者由应用程序针对这个套接字调用WSAAsyncSelect,从而更改注册的网络事件类型,否则网络事件总是有效。若将lEvent设为0,则效果相当于停止在套接字上进行的所有网络事件通知。
若应用程序针对一个套接字调用WSAsyncSelect,那么套接字的模式会从阻塞模式自动转换为非阻塞模式。
演示WSAAsyncSelect程序基本流程:
#include<windows.h> #include<winsock2.h> #pragma comment(lib, "ws2_32.lib") #define WM_SOCKET WM_USER+1 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WSADATA wsaData; SOCKET Listen; SOCKADDR_IN addr; HWND window; //创建窗口 window = CreateWindow(); WSAStartup(MAKEWORD(2,2), &wsaData); Listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); memset(addr, 0, sizeof(SOCKADDR_IN)); addr.sin_family = AF_INET; addr.sin_port = htons(5050); addr.sin_addr.s_addr = hotnl(INADDR_ANY); bind(Listen, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN)); //使用定义的WM_SOCKET 在新套接字上设置窗口消息通知 WSAAsyncSelect(Listen, window, WM_SOCKET, FD_ACCEPT|FD_CLOSE); listen(Listen, 5); //转换并分配消息 while(1) { ... } } BOOL CALLBACK ServerProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam) { SOCKET Accept; switch(wMsg) { case WM_PAINT: break; case WM_SOCKET: //使用WSAGETSELECTERROR宏来判断套接字上是否发生了错误 if(WSAGETSELECTERROR(lParam)) { //显示错误,关闭套接字 closesocket((SOCKET)wParam); break; } //确定在套接字上发生什么事件 switch(WSAGETSELECTEVENT(lParam)) { case FD_ACCEPT: //接受一个传入的连接 Accept = accept(wParam, NULL, NULL); //让接收套接字为读写及关闭通知做好准备 WSAAsyncSelect(Accept, hDlg, WM_SOCKET, FD_READ|FD_WRITE|FD_CLOSE); break; case FD_READ: //从wParam中的套接字中检索数据 break; case FD_WRITE: //wParam中的套接字已准备好发送数据 break; case FD_CLOSE: closesocket((SOCKET)wParam); break; } break; } return true; }
最后一个特别有价值的问题是应用程序如何对FD_WRITE事件通知进行处理,只有3种条件下,FD_WRITE通知才会发出:
1.使用connect或WSAConnect,一个套接字首次建立连接
2.使用accept或WSAAccept,套接字被接受以后
3.若send,WSASend,sendto或WSASendTo操作失败,返回了WSAEWOULDBLOCK错误,而且缓冲区的空间变得可用时
优点是它可以在系统开销不大的情况下同时处理许多连接,而select需要建立fd_set结构。
缺点是即使应用程序不需要窗口,它也不得不额外使用一个窗口。同时,用一个单窗口程序来处理成千上万的套接字中的所有事件,很可能成为性能瓶颈。
========================================================================
服务器端得主要流程:
1.在WM_CREATE消息处理函数中,初始化Windows Socket library,创建监听套接字,绑定,监听,并且调用WSAAsyncSelect函数表示我们关心在监听套接字上发生的FD_ACCEPT事件;
2.自定义一个消息WM_SOCKET,一旦在我们所关心的套接字(监听套接字和客户端套接字)上发生了某个事件,系统就会调用WndProc并且message参数被设置为WM_SOCKET;
3.在WM_SOCKET的消息处理函数中,分别对FD_ACCEPT、FD_READ和FD_CLOSE事件进行处理;
4.在窗口销毁消息(WM_DESTROY)的处理函数中,我们关闭监听套接字,清除Windows Socket library
WSAAsyncSelect函数的网络事件类型可以有以下一种:
FD_READ 应用程序想要接收有关是否可读的通知,以便读入数据
FD_WRITE 应用程序想要接收有关是否可写的通知,以便写入数据
FD_OOB 应用程序想接收是否有带外(OOB)数据抵达的通知
FD_ACCEPT 应用程序想接收与进入连接有关的通知
FD_CONNECT 应用程序想接收与一次连接或者多点join操作完成的通知
FD_CLOSE 应用程序想接收与套接字关闭有关的通知
FD_QOS 应用程序想接收套接字“服务质量”(QoS)发生更改的通知
FD_GROUP_QOS 应用程序想接收套接字组“服务质量”发生更改的通知(现在没什么用处,为未来套接字组的使用保留)
FD_ROUTING_INTERFACE_CHANGE 应用程序想接收在指定的方向上,与路由接口发生变化的通知
FD_ADDRESS_LIST_CHANGE 应用程序想接收针对套接字的协议家族,本地地址列表发生变化的通知
#include<windows.h> #include<winsock2.h> #include<tchar.h> #pragma comment(lib, "ws2_32.lib") #define WM_SOCKET WM_USER+1 #define PORT 5050 #define MSGSIZE 1024 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpCmdLine, int nCmdShow) { static TCHAR szAppName[] = _T("WSAAsyncSelect Mode"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if(!RegisterClass(&wndclass)) { MessageBox(NULL, _T("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, _T("WSAAsyncSelect Mode"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { WSADATA wsaData; static SOCKET sListen; SOCKET sClient; SOCKADDR_IN local, client; int ret; int iAddrSize = sizeof(SOCKADDR_IN); char szMessage[MSGSIZE]; switch(message) { case WM_CREATE: WSAStartup(MAKEWORD(2,2), &wsaData); sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); memset(local, 0, sizeof(SOCKADDR_IN)); local.sin_family = AF_INET; local.sin_port = htons(PORT); local.sin_addr.s_addr = htonl(INADDR_ANY); bind(sListen, (SOCKADDR*)&local, sizeof(SOCKADDR_IN)); listen(sListen, 5); WSAAsyncSelect(sListen, hwnd, WM_SOCKET, FD_ACCEPT); return 0; case WM_DESTROY: closesocket(sListen); WSACleanup(); PostQuitMessage(0); return 0; case WM_SOCKET: if(GETSELECTERROR(lParam)) { closesocket(wParam); break; } switch(GETSELECTEVENT(lParam)) { case FD_ACCEPT: sClient = accept(wParam, (SOCKADDR*)&client, &iAddrSize); WSAAsyncSelect(sClient, hwnd, WM_SOCKET, FD_READ | FD_CLOSE); break; case FD_READ: ret = recv(wParam, szMessage, MSGSIZE, 0); if(ret==0||(ret==SOCKET_ERROR && WSAGetLastError()==WSAECONNRESET)) { closesocket(wParam); } else { szMessage[ret]='\0'; send(wParam, szMesage, strlen(szMessage), 0); } break; case FD_CLOSE: closesocket(wParam); break; } return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
相关文章推荐
- 套接字I/O模型-WSAAsyncSelect
- WSAAsyncSelect异步套接字模型Client——》Server
- 套接字I/O模型之 消息机制-WSAAsyncSelect
- 套接字的select、WsaAsyncSelect、WsaEventSelect模型
- WSAAsyncselect 模型中,服务器与客户端消息的收发
- (转)套接字IO模型(三) WSAEventSelect模型
- Winsock异步模型之(事件通知模型 WSAAsyncSelect)
- 二、异步选择模型(WSAAsyncSelect)
- WinSock IO模型二: WSAAsyncSelect 消息机制
- 套接字I/O模型之三--WSAEventSelect
- TCP,UDP IO模型(一)WSAAsyncSelect 异步选择
- Windows操作系统I/O模型—笔记2(异步选择(WSAAsyncSelect)模型)
- Winsock异步事件通知模型WSAAsyncSelect
- WSAAsyncSelect和windows客户端异步IO模型
- 套接字I/O模型-WSAEventSelect
- (二)Socket I/O模型之异步选择(WSAAsyncSelect)
- WinSock---WSAAsyncSelect IO模型和select模型的比较
- 多种SOKECT通讯模型的理解(select,WSAAsyncSelect,WSAEventSelect,Overlapped I/O 事件通知,Overlapped I/O 完成例程,IOCP)
- Windows套接字I/O模型(4) -- WSAEventSelect模型
- [转载]使用 WSAAsyncSelect 的 Winsock 编程模型