套接字I/O模型-WSAAsyncSelect
利用这个异步I/O模型,应用程序可在一个套接字上接收以Windows消息为基础的网络事件通知。WSAAsyncSelect和WSAEventSelect提供读写数据能力的异步通知,但它们不提供异步数据传输,重叠及完成端口提供异步数据传输。
消息通知
要想使用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(,), &wsaData);
Listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
memset(addr, , sizeof(SOCKADDR_IN));
addr.sin_family = AF_INET;
addr.sin_port = htons();
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, );
//转换并分配消息
while()
{
...
}
} 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通知才会发出:
.使用connect或WSAConnect,一个套接字首次建立连接
.使用accept或WSAAccept,套接字被接受以后
.若send,WSASend,sendto或WSASendTo操作失败,返回了WSAEWOULDBLOCK错误,而且缓冲区的空间变得可用时
优点是它可以在系统开销不大的情况下同时处理许多连接,而select需要建立fd_set结构。
缺点是即使应用程序不需要窗口,它也不得不额外使用一个窗口。同时,用一个单窗口程序来处理成千上万的套接字中的所有事件,很可能成为性能瓶颈。 ======================================================================== 服务器端得主要流程:
.在WM_CREATE消息处理函数中,初始化Windows Socket library,创建监听套接字,绑定,监听,并且调用WSAAsyncSelect函数表示我们关心在监听套接字上发生的FD_ACCEPT事件;
.自定义一个消息WM_SOCKET,一旦在我们所关心的套接字(监听套接字和客户端套接字)上发生了某个事件,系统就会调用WndProc并且message参数被设置为WM_SOCKET;
.在WM_SOCKET的消息处理函数中,分别对FD_ACCEPT、FD_READ和FD_CLOSE事件进行处理;
.在窗口销毁消息(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 = ;
wndclass.cbWndExtra = ;
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 ;
}
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, , ))
{
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(,), &wsaData);
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
memset(local, , 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, );
WSAAsyncSelect(sListen, hwnd, WM_SOCKET, FD_ACCEPT);
return ;
case WM_DESTROY:
closesocket(sListen);
WSACleanup();
PostQuitMessage();
return ;
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, );
if(ret==||(ret==SOCKET_ERROR && WSAGetLastError()==WSAECONNRESET))
{
closesocket(wParam);
}
else
{
szMessage[ret]='\0';
send(wParam, szMesage, strlen(szMessage), );
}
break;
case FD_CLOSE:
closesocket(wParam);
break;
}
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
套接字I/O模型-WSAAsyncSelect的更多相关文章
- 套接字I/O模型-select
共有6种类型套接字I/O模型.blocking(阻塞),select(选择),WSAAsyncSelect(异步选择),WSAEventSelect(事件选择),overlapped(重叠),comp ...
- 套接字I/O模型之WSAEventSelect
今天我又学习了一种新的套接字I/O模型------WSAEventSelect,他与WSAAsyncSelect一样也是一种异步事件通知模型,不同的是WSAAsyncSelect是与窗口句柄关联在一起 ...
- 套接字I/O模型-WSAEventSelect(转载)
和WSAAsyncSelect类似,它也允许应用程序在一个或多个套接字上,接收以事件为基础的网络事件通知. 该模型最主要的区别是在于网络事件是由对象句柄完成的,而不是通过窗口例程完成. 事件通知 事件 ...
- Windsock套接字I/O模型学习 --- 第三章
1. WSAAsyncSelect 模型 WSAAsyncSelect 模型比较简单,是为了适应Windows的消息驱动环境而设置的,WSAAsyncSelect 函数自动把套接字设为非阻塞模式.MF ...
- Windsock套接字I/O模型学习 --- 第一章
1. I/O模型共有以下几种: 阻塞(blocking)模型 选择(select)模型 WSAAsyncSelect模型 WSAEventSelect模型 重叠(overlapped)模型 完成端口( ...
- 套接字I/O模型-重叠I/O
重叠模型的基本设计原理是让应用程序使用重叠的数据结构,一次投递一个或多个WinsockI/O请求.针对那些提交的请求,在它们完成之后,应用程序可为它们提供服务.模型的总体设计以Windows重叠I/O ...
- 套接字I/O模型-完成端口IOCP
“完成端口”模型是迄今为止最为复杂的一种I/O模型.然而,假若一个应用程序同时需要管理为数众多的套接字,那么采用这种模型,往往可以达到最佳的系统性能!但不幸的是,该模型只适用于Windows NT和W ...
- Linux下套接字具体解释(三)----几种套接字I/O模型
參考: 网络编程–IO模型演示样例 几种server端IO模型的简介及实现 背景知识 堵塞和非堵塞 对于一个套接字的 I/O通信,它会涉及到两个系统对象.一个是调用这个IO的进程或者线程,还有一个就是 ...
- Windsock套接字I/O模型学习 --- 第二章
1. select模型 select模型主要借助于apiselect来实现,所以先介绍一下select函数 int select( int nfds, // 忽略,仅是为了与 Berkeley 套接字 ...
随机推荐
- iOS App上架流程(2016详细版
http://www.jianshu.com/p/b1b77d804254 iOS App上传项目遇到的问题 http://www.jianshu.com/p/9195cd991fc7
- (转)Eclipse “cannot be resolved to a type” error
原:http://www.cnblogs.com/xuxm2007/archive/2011/10/20/2219104.html Eclipse “cannot be resolved to a t ...
- UIkit框架之Uivew
1.继承链:UIresponder:NSObject 2.通过使用 addGestureRecognizer:方法可以为视图添加手势 3.下面的属性都可以用来用于动画 @property frame ...
- BZOJ 1271 秦腾与教学评估
二分. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> ...
- 【LeetCode OJ】Populating Next Right Pointers in Each Node II
Problem Link: http://oj.leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/ OK... ...
- office2010安装Microsoft Office Document Imaging (MODI) 图解
office2010安装Microsoft Office Document Imaging (MODI) 图解 Microsoft Office 2010 中删除了 Microsoft Off ...
- 使用RBL拦截垃圾邮件
1. sbl-xbl.spamhaus.org 2 bl.spamcop.net 3 zen.spamhaus.org
- 第一个Sprint冲刺事后诸葛报告
用户反馈:软件一般般,比较传统. 用户数量:5 团队改进建议:选择题与填空题太没有新意了,需要新的创新功能. 1.每个成员第一个sprint阶段有何需要改进? 成员 需要改进 邵家文 需要更多的技术的 ...
- c++ encode decode
std::string UrlEncode(const std::string& szToEncode) { std::string src = szToEncode; char hex[] ...
- Windows上的文件合并命令
从Linux转到Windowns后,发现很多好用的shell命令都没有了,但实际情况是Windows一样有DOS时代的命令窗口,在CLI年代用DOS的人也要干活. 比如,今天想将几个单独的sql文件整 ...