Windows套接字I/O模型(3) -- WSAAsyncSelect模型
一、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模型相关推荐
- MFC—windows套接字编程
Windows 套接字编程 一.常见概念 1.Windows Sockets 规范 Windows Sockets 规范是 Windows 平台下定义的可以兼容二进制数据传输的网络编程接口,是基于伯克 ...
- Windows Socket套接字(四)-Windows套接字错误代码
WSAGetLastError函数 int WSAGetLastError(void); 返回值表示该线程的最后一个Windows Sockets操作失败的错误代码. 在Winsock应用程序中,使用 ...
- “ windows套接字初始化失败”解决方法
出现问题: 启动电脑后,点开部分软件出现"Windows套接字初始化失败",浏览器不能上网. 解决方案一: 1.开始--运行--CMD--右击,选择使用管理员权限运行 2.cmd内 ...
- Windows套接字(Socket)例子(源码,实例)
最简单的Windows套接字(Socket)例子(源码,实例) 佟强(http://blog.csdn.net/microtong) 2008年11月21日 Server.exe PortNumber ...
- Win8.1系统“Windows 套接字初始化失败”解决方案
[前言] 那是一个炎热夏日的午后,打开电脑,本来就没睡醒的我,更懵了. 上来就是个窗口: Windows 通信端口初始化失败. 电脑管家说:登录组件错误[4],请重新启动电脑管家. ...
- Windows套接字I/O模型(4) -- WSAEventSelect模型
一.WSAEventSelect模型介绍 WSAEventSelect模型和WSAAsyncSelect模型类似,它也允许应用程序在一个或多个套接字上面,接收以事件为基础的网络事件通知.该模型和WSA ...
- Windows套接字I/O模型(2) -- Select模型
一.Select模型介绍 套接字I/O Select模型的"中心思想"便是利用select函数,实现对I/O的管理.利用select函数判断套接字(一个或多个)上是否存在数据,或者 ...
- windows套接字IOCP模型
本文主要探讨一下windows平台上的完成端口开发及其与之相关的几个重要的技术概念,这些概念都是与基于IOCP的开发密切相关的,对开发人员来讲,又不得不给予足够重视的几个概念: 1) 基于IOCP实现 ...
- 套接字I/O模型-重叠I/O
重叠模型的基本设计原理是让应用程序使用重叠的数据结构,一次投递一个或多个WinsockI/O请求.针对那些提交的请求,在它们完成之后,应用程序可为它们提供服务.模型的总体设计以Windows重叠I/O ...
- Windows下套接字
一.套接字 windows套接字Socket是进程通信的一种方式,可以实现在不同主机的相关进程之间交换数据.在TCP/IP网络应用中,通信的两个进程的主要模式是客户/服务器(C/S)模式,即客 ...
最新文章
- 转:Flutter Decoration背景设定(边框、圆角、阴影、形状、渐变、背景图像等)...
- 2- 计算机的组成,VMware使用
- 【windows gdi+】GDI+ Image类加载图片时异常问题处理与分析
- python 循环添加array_Python的备忘细节小抄
- 【软考-软件设计师】解释程序实现高级语言的三种方式
- 将图卷积神经网络用于解码分子生成
- java api接口报500_应用程序编程接口API,我们来聊一聊这个熟悉的名词
- SAP 基于 ABAP 实现的 gateway 框架里,为什么默认返回100条数据?
- linux环境下最简单的C语言例子
- 深入理解张正友相机标定法:数学理论详细推导
- 沈抚示范区·“华为云杯”2021全国AI大赛圆满落幕
- Qt中出现0xc0000135错误
- iOS制作微信(weChat)支付SDK过程
- 题解 - HDU 6638 Snowy Smile (线段树)
- 怎么查看计算机簇大小,分区格式与簇的大小讲解
- Cent OS (一)Cents OS的基本安装
- Python之面向对象
- 国丰帮您-采用LDP作为VPLS信令建立PW--VPLS示例
- android2012系统,压倒性份额四核技术 Android系统2012前瞻
- layui文件上传后台(带自定参数)