一、WSAAsyncSelect模型介绍

利用WSAAsyncSelect模型,结合windows窗口消息循环,应用程序可以在一个套接字上,接收以windows消息为基础的网络事件通知。要想使用WSAAsyncSelect模型,首先必须创建一个窗口,并为窗口提供一个窗口过程支持函数。

int WSAAsyncSelect(_In_ SOCKET       s,_In_ HWND         hWnd,_In_ unsigned int wMsg,_In_ long         lEvent
);

s 指定我们感兴趣的套接字。
hWnd 指定一个窗口句柄,它表示网络事件发生之后,收到消息通知的那个窗口。
wMsg 表示在网络事件发生时,窗口收到的消息。
lEvent 代表一个掩码,指定应用程序感兴趣的网络事件的组合。事件类型包括:FD_READ,FD_WRITE,FD_CLOSE,FD_CONNECT,FD_ACCEPT。对于FD_CONNECT,FD_ACCEPT,服务端一般使用FD_ACCEPT,客户端一般使用FD_CONNECT。若将lEvent设置为0,则表示停止接收该套接字上的所有网络事件通知。

一旦调用WSAAsyncSelect在套接字上启用了事件通知,除非明确调用closesocket,或者再次调用WSAAsyncSelect重新设置网络事件类型,否则,事件通知总是有效的。

WSAAsyncSelect模型需要结合windows窗口来使用,不适用于没有界面的服务程序。建议使用WSAEventSelect模型来代替。

二、示例

因为重点不在界面编程上面,所以示例中使用TraceMsgA打印信息到visual studio的输出窗口或debugview。
InitWindow函数用于创建一个简单的、空白的窗口,将句柄存储在全局变量g_hwnd中。
WndProc为窗口的处理过程函数。

服务端在有新的客户端连接上时,给客户端发送“hello, I’m server.”消息,在服务端退出时,关闭所有客户端连接。
客户端连接上服务端之后,接收服务端的消息。

2.1 服务端

#include <winsock2.h>
#include <vector>
#include <strsafe.h>#pragma comment(lib, "Ws2_32.lib")const u_short kPort = 10001;
const std::string kHelloServer = "hello, I'm server.";#define WUM_SOCKET (WM_USER+1)HWND g_hwnd;SOCKET socket_srv = INVALID_SOCKET;
std::vector<SOCKET> clients;void TraceMsgA(const char *lpFormat, ...) {if (!lpFormat)return;char *pMsgBuffer = NULL;unsigned int iMsgBufCount = 0;va_list arglist;va_start(arglist, lpFormat);HRESULT hr = STRSAFE_E_INSUFFICIENT_BUFFER;while (hr == STRSAFE_E_INSUFFICIENT_BUFFER) {iMsgBufCount += 1024;if (pMsgBuffer) {free(pMsgBuffer);pMsgBuffer = NULL;}pMsgBuffer = (char*)malloc(iMsgBufCount * sizeof(char));if (!pMsgBuffer) {break;}hr = StringCchVPrintfA(pMsgBuffer, iMsgBufCount, lpFormat, arglist);}va_end(arglist);if (hr == S_OK) {OutputDebugStringA(pMsgBuffer);}if (pMsgBuffer) {free(pMsgBuffer);pMsgBuffer = NULL;}
}LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{int err;SOCKET s;char buf[100] = { 0 };switch (message) {// (5)case WUM_SOCKET:if (WSAGETSELECTERROR(lParam)) {closesocket((SOCKET)wParam);break;}switch (WSAGETSELECTEVENT(lParam)){case FD_ACCEPT:s = accept((SOCKET)wParam, NULL, NULL);clients.push_back(s);WSAAsyncSelect(s, g_hwnd, WUM_SOCKET, FD_READ | FD_WRITE | FD_CLOSE);TraceMsgA("new connection\n");err = send(s, (const char*)kHelloServer.c_str(), kHelloServer.length(), 0);if (err == SOCKET_ERROR) {TraceMsgA("send failed, GLE: %d\n", WSAGetLastError());break;}break;case FD_READ:err = recv((SOCKET)wParam, buf, 100, 0);if (err > 0) {TraceMsgA("recv: %s\n", buf);}else if (err == 0) {TraceMsgA("connection closed\n");closesocket((SOCKET)wParam);}else {TraceMsgA("recv failed, GLE: %d\n", WSAGetLastError());closesocket((SOCKET)wParam);}break;case FD_WRITE:break;case FD_CLOSE:closesocket((SOCKET)wParam);for (std::vector<SOCKET>::iterator it = clients.begin(); it != clients.end(); it++) {if (*it == (SOCKET)wParam) {clients.erase(it);break;}}break;}break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0;
}void InitWindow(HINSTANCE hInstance) {WCHAR szWindowClass[100] = L"Test";WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };wcex.style = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0;wcex.cbWndExtra = 0;wcex.hInstance = hInstance;wcex.lpszClassName = szWindowClass;RegisterClassExW(&wcex);g_hwnd = CreateWindowW(szWindowClass, L"server", WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);if (g_hwnd) {ShowWindow(g_hwnd, SW_SHOW);UpdateWindow(g_hwnd);}
}int APIENTRY wWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPWSTR    lpCmdLine,_In_ int       nCmdShow)
{UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);InitWindow(hInstance);WSADATA wsaData;WORD wVersionRequested = MAKEWORD(2, 2);WSAStartup(wVersionRequested, &wsaData);do{// (1)socket_srv = ::socket(AF_INET, SOCK_STREAM, 0);if (socket_srv == INVALID_SOCKET) {TraceMsgA("create socket failed, GLE: %d\n", WSAGetLastError());break;}// (2)struct sockaddr_in addr = { 0 };addr.sin_family = AF_INET;addr.sin_addr.s_addr = htonl(INADDR_ANY);addr.sin_port = htons(kPort);if (bind(socket_srv, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)) == SOCKET_ERROR) {TraceMsgA("bind failed, GLE: %d\n", WSAGetLastError());break;}// (3)WSAAsyncSelect(socket_srv, g_hwnd, WUM_SOCKET, FD_ACCEPT | FD_READ | FD_WRITE | FD_CLOSE);// (4)if (listen(socket_srv, 5) == SOCKET_ERROR) {TraceMsgA("listen failed, GLE: %d\n", WSAGetLastError());break;}TraceMsgA("listen on port: %d\n", kPort);} while (false);MSG msg;while (GetMessage(&msg, nullptr, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg);}for (std::vector<SOCKET>::iterator it = clients.begin(); it != clients.end(); it++) {closesocket(*it);}// (6)closesocket(socket_srv);WSACleanup();return 0;
}

2.2 客户端

#include <winsock2.h>
#include <vector>
#include <strsafe.h>#pragma comment(lib, "Ws2_32.lib")const std::string kIP = "127.0.0.1";
const u_short kPort = 10001;#define WUM_SOCKET (WM_USER+1)HWND g_hwnd;void TraceMsgA(const char *lpFormat, ...) {if (!lpFormat)return;char *pMsgBuffer = NULL;unsigned int iMsgBufCount = 0;va_list arglist;va_start(arglist, lpFormat);HRESULT hr = STRSAFE_E_INSUFFICIENT_BUFFER;while (hr == STRSAFE_E_INSUFFICIENT_BUFFER) {iMsgBufCount += 1024;if (pMsgBuffer) {free(pMsgBuffer);pMsgBuffer = NULL;}pMsgBuffer = (char*)malloc(iMsgBufCount * sizeof(char));if (!pMsgBuffer) {break;}hr = StringCchVPrintfA(pMsgBuffer, iMsgBufCount, lpFormat, arglist);}va_end(arglist);if (hr == S_OK) {OutputDebugStringA(pMsgBuffer);}if (pMsgBuffer) {free(pMsgBuffer);pMsgBuffer = NULL;}
}LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{int err;SOCKET s;char buf[100] = { 0 };switch (message) {// (4)case WUM_SOCKET:if (WSAGETSELECTERROR(lParam)) {closesocket((SOCKET)wParam);TraceMsgA("connect failed, %d\n", WSAGETSELECTERROR(lParam));break;}switch (WSAGETSELECTEVENT(lParam)){case FD_CONNECT:TraceMsgA("connection to server\n");break;case FD_READ:err = recv((SOCKET)wParam, buf, 100, 0);if (err > 0) {TraceMsgA("recv: %s\n", buf);}else if (err == 0) {closesocket((SOCKET)wParam);TraceMsgA("connection closed\n");}else {closesocket((SOCKET)wParam);TraceMsgA("recv failed, GLE: %d\n", WSAGetLastError());}break;case FD_WRITE:break;case FD_CLOSE:closesocket((SOCKET)wParam);TraceMsgA("connection closed\n");break;}break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0;
}void InitWindow(HINSTANCE hInstance) {WCHAR szWindowClass[100] = L"Test";WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };wcex.style = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc = WndProc;wcex.cbClsExtra = 0;wcex.cbWndExtra = 0;wcex.hInstance = hInstance;wcex.lpszClassName = szWindowClass;RegisterClassExW(&wcex);g_hwnd = CreateWindowW(szWindowClass, L"client", WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);if (g_hwnd) {ShowWindow(g_hwnd, SW_SHOW);UpdateWindow(g_hwnd);}
}int APIENTRY wWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPWSTR    lpCmdLine,_In_ int       nCmdShow)
{UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);InitWindow(hInstance);WSADATA wsaData;WORD wVersionRequested = MAKEWORD(2, 2);WSAStartup(wVersionRequested, &wsaData);SOCKET socket_ = INVALID_SOCKET;do{// (1)socket_ = ::socket(AF_INET, SOCK_STREAM, 0);if (socket_ == INVALID_SOCKET) {TraceMsgA("create socket failed, GLE: %d\n", WSAGetLastError());break;}// (2)WSAAsyncSelect(socket_, g_hwnd, WUM_SOCKET, FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE);// (3)struct sockaddr_in addr = { 0 };addr.sin_family = AF_INET;addr.sin_addr.s_addr = inet_addr(kIP.c_str());addr.sin_port = htons(kPort);if (connect(socket_, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)) == SOCKET_ERROR) {int gle_err = WSAGetLastError();if (gle_err != WSAEWOULDBLOCK) {TraceMsgA("connect failed, GLE: %d\n", WSAGetLastError());break;}}} while (false);MSG msg;while (GetMessage(&msg, nullptr, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg);}// (5)closesocket(socket_);WSACleanup();return 0;
}

代码下载地址: http://download.csdn.net/download/china_jeffery/10155511

Windows套接字I/O模型(3) -- WSAAsyncSelect模型相关推荐

  1. MFC—windows套接字编程

    Windows 套接字编程 一.常见概念 1.Windows Sockets 规范 Windows Sockets 规范是 Windows 平台下定义的可以兼容二进制数据传输的网络编程接口,是基于伯克 ...

  2. Windows Socket套接字(四)-Windows套接字错误代码

    WSAGetLastError函数 int WSAGetLastError(void); 返回值表示该线程的最后一个Windows Sockets操作失败的错误代码. 在Winsock应用程序中,使用 ...

  3. “ windows套接字初始化失败”解决方法

    出现问题: 启动电脑后,点开部分软件出现"Windows套接字初始化失败",浏览器不能上网. 解决方案一: 1.开始--运行--CMD--右击,选择使用管理员权限运行 2.cmd内 ...

  4. Windows套接字(Socket)例子(源码,实例)

    最简单的Windows套接字(Socket)例子(源码,实例) 佟强(http://blog.csdn.net/microtong) 2008年11月21日 Server.exe PortNumber ...

  5. Win8.1系统“Windows 套接字初始化失败”解决方案

    [前言] 那是一个炎热夏日的午后,打开电脑,本来就没睡醒的我,更懵了. 上来就是个窗口: Windows 通信端口初始化失败.       电脑管家说:登录组件错误[4],请重新启动电脑管家.     ...

  6. Windows套接字I/O模型(4) -- WSAEventSelect模型

    一.WSAEventSelect模型介绍 WSAEventSelect模型和WSAAsyncSelect模型类似,它也允许应用程序在一个或多个套接字上面,接收以事件为基础的网络事件通知.该模型和WSA ...

  7. Windows套接字I/O模型(2) -- Select模型

    一.Select模型介绍 套接字I/O Select模型的"中心思想"便是利用select函数,实现对I/O的管理.利用select函数判断套接字(一个或多个)上是否存在数据,或者 ...

  8. windows套接字IOCP模型

    本文主要探讨一下windows平台上的完成端口开发及其与之相关的几个重要的技术概念,这些概念都是与基于IOCP的开发密切相关的,对开发人员来讲,又不得不给予足够重视的几个概念: 1) 基于IOCP实现 ...

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

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

  10. Windows下套接字

    一.套接字     windows套接字Socket是进程通信的一种方式,可以实现在不同主机的相关进程之间交换数据.在TCP/IP网络应用中,通信的两个进程的主要模式是客户/服务器(C/S)模式,即客 ...

最新文章

  1. 转:Flutter Decoration背景设定(边框、圆角、阴影、形状、渐变、背景图像等)...
  2. 2- 计算机的组成,VMware使用
  3. 【windows gdi+】GDI+ Image类加载图片时异常问题处理与分析
  4. python 循环添加array_Python的备忘细节小抄
  5. 【软考-软件设计师】解释程序实现高级语言的三种方式
  6. 将图卷积神经网络用于解码分子生成
  7. java api接口报500_应用程序编程接口API,我们来聊一聊这个熟悉的名词
  8. SAP 基于 ABAP 实现的 gateway 框架里,为什么默认返回100条数据?
  9. linux环境下最简单的C语言例子
  10. 深入理解张正友相机标定法:数学理论详细推导
  11. 沈抚示范区·“华为云杯”2021全国AI大赛圆满落幕
  12. Qt中出现0xc0000135错误
  13. iOS制作微信(weChat)支付SDK过程
  14. 题解 - HDU 6638 Snowy Smile (线段树)
  15. 怎么查看计算机簇大小,分区格式与簇的大小讲解
  16. Cent OS (一)Cents OS的基本安装
  17. Python之面向对象
  18. 国丰帮您-采用LDP作为VPLS信令建立PW--VPLS示例
  19. android2012系统,压倒性份额四核技术 Android系统2012前瞻
  20. layui文件上传后台(带自定参数)

热门文章

  1. 计算机培训日志范文30篇,班主任工作日志20篇.docx
  2. 建筑物后期调色ps动作
  3. 微信企业号上传永久素材讲解与演示
  4. 投资理财--动态市盈率静态市盈率 整理
  5. 【教程】Gentoo的安装
  6. i春秋 - Exploit-Exercises: Nebula - level06
  7. 小猫钓鱼纸牌游戏java_java实现纸牌游戏之小猫钓鱼算法
  8. 带你Dart带你Diao之类(一)
  9. 微信/QQ/TIM消息防撤回最新补丁
  10. java web调用海康威视摄像头