利用这个异步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的更多相关文章

  1. 套接字I/O模型-select

    共有6种类型套接字I/O模型.blocking(阻塞),select(选择),WSAAsyncSelect(异步选择),WSAEventSelect(事件选择),overlapped(重叠),comp ...

  2. 套接字I/O模型之WSAEventSelect

    今天我又学习了一种新的套接字I/O模型------WSAEventSelect,他与WSAAsyncSelect一样也是一种异步事件通知模型,不同的是WSAAsyncSelect是与窗口句柄关联在一起 ...

  3. 套接字I/O模型-WSAEventSelect(转载)

    和WSAAsyncSelect类似,它也允许应用程序在一个或多个套接字上,接收以事件为基础的网络事件通知. 该模型最主要的区别是在于网络事件是由对象句柄完成的,而不是通过窗口例程完成. 事件通知 事件 ...

  4. Windsock套接字I/O模型学习 --- 第三章

    1. WSAAsyncSelect 模型 WSAAsyncSelect 模型比较简单,是为了适应Windows的消息驱动环境而设置的,WSAAsyncSelect 函数自动把套接字设为非阻塞模式.MF ...

  5. Windsock套接字I/O模型学习 --- 第一章

    1. I/O模型共有以下几种: 阻塞(blocking)模型 选择(select)模型 WSAAsyncSelect模型 WSAEventSelect模型 重叠(overlapped)模型 完成端口( ...

  6. 套接字I/O模型-重叠I/O

    重叠模型的基本设计原理是让应用程序使用重叠的数据结构,一次投递一个或多个WinsockI/O请求.针对那些提交的请求,在它们完成之后,应用程序可为它们提供服务.模型的总体设计以Windows重叠I/O ...

  7. 套接字I/O模型-完成端口IOCP

    “完成端口”模型是迄今为止最为复杂的一种I/O模型.然而,假若一个应用程序同时需要管理为数众多的套接字,那么采用这种模型,往往可以达到最佳的系统性能!但不幸的是,该模型只适用于Windows NT和W ...

  8. Linux下套接字具体解释(三)----几种套接字I/O模型

    參考: 网络编程–IO模型演示样例 几种server端IO模型的简介及实现 背景知识 堵塞和非堵塞 对于一个套接字的 I/O通信,它会涉及到两个系统对象.一个是调用这个IO的进程或者线程,还有一个就是 ...

  9. Windsock套接字I/O模型学习 --- 第二章

    1. select模型 select模型主要借助于apiselect来实现,所以先介绍一下select函数 int select( int nfds, // 忽略,仅是为了与 Berkeley 套接字 ...

随机推荐

  1. zoj1530 bfs

    //Accepted zoj1530 270ms 40008KB #include <cstdio> #include <cstring> #include <iostr ...

  2. C++的三种继承方式简述

    C++对父类(也称基类)的继承有三种方式,分别为:public继承.protected继承.private继承.三种继承方式的不同在于继承之后子类的成员函数的"可继承性质". 在说 ...

  3. java equals 和hashcode

    1  如果不知道怎么重载hashcode, eclipse自动代码生成工具会帮助你生成,大概的思路是设定一个int prim,  然后根据各个成员的值或者hashcode值进行某种运算即可,具体什么运 ...

  4. Varnost slovenskih GSM omrežij III

    V torek smo pisali tudi o tem, da Si.Mobil v svojem omrežju dovoli uporabo A5/0 (nešifriranega preno ...

  5. 自定义UIPageControl

    iphone的UIPageControl控件可以显示用户huan'dong滑动到的页码.但是里面的小点的颜色时默认的白色.如果背景也是白色的hu话,你就悲剧了.于是乎上网找了一些资料,找到了改变UIP ...

  6. 解决:Android编译源码根目录下/system/vold后,通过push命令将编译生成的vold文件push至system/bin下无法正常开机

    这段时间由于工作需要,在对android根目录下/system/vold进行修改编译的时候,在通过adb命令将vold文件push至/system/bin目录下,adb reboot重启手机却发现一直 ...

  7. 转载:socket.io 入门

    原文链接:http://cnodejs.org/topic/50a1fcc7637ffa4155b5a264 我自己在用socket.io开发,对官方网站上的文档,进行简单的整理,然后自己写了一个简单 ...

  8. Maven Build profiles

    They modify the POM at build time, and are meant to be used in complementary sets to give equivalent ...

  9. 【LeetCode OJ】Pascal's Triangle II

    Problem Link: http://oj.leetcode.com/problems/pascals-triangle-ii/ Let T[i][j] be the j-th element o ...

  10. AngularJS基本指令

    <!doctype html> <html  ng-app> <head>   <meta charset="UTF-8">   & ...