zoukankan      html  css  js  c++  java
  • WSAAsyncSelect模型

    WSAAsyncSelect模型是Windows Socket的一个异步I/O模型。
    利用该模型可以接收以Windows消息为基础的socket网络事件。
    Windows sockets应用程序在创建套接字后,调用WSAAsyncSelect函数注册感兴趣的网络事件,当该事件发生时Windows窗口收到消息,应用程序就可以对接收到的网络事件进行处理。
     
    WSAAsyncSelect是select模型的异步版本。在应用程序使用select函数时会发生阻塞现象。可以通过select的timeout参数设置阻塞的时间。在设置的时间内,select函数等待,直到一个或多个Socket满足可读或可写的条件。
     

    而WSAAsyncSelect是非阻塞的。Windows sockets程序在调用recv之前,调用WSAAsyncSelect注册网络事件。WSAAsyncSelect函数立即返回。当系统中数据准备好时,会向应用程序发送消息。此此消息的处理函数中可以调用recv接收数据。


     WSAAsyncSelect模型与select模型的相同点是它们都可以对多个套接字进行管理。但它们也有不小的区别。

    首先WSAAsyncSelect模型是异步的,且通知方式不同。

    更重要的一点是:WSAAsyncSelect模型应用在基于消息的Windows环境下,使用该模型时必须创建窗口,而select模型可以广泛应用在Unix系统,使用该模型不需要创建窗口。

    最后一点区别:应用程序在调用WSAAsyncSelect函数后,套接字就被设置为非阻塞状态。而使用select函数不改变套接字的工作方式。

    #define _WINSOCK_DEPRECATED_NO_WARNINGS
    #include <winsock2.h>
    #include <windows.h>
    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    #pragma comment(lib, "ws2_32.lib")
    #define WM_SOCKET (WM_USER + 1)
    #define MAXDATASIZE	1024
    
    
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);//回调函数
    
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    	PSTR szCmdLine, int iCmdShow)
    {
    	static TCHAR szAppName[] = TEXT("WSAAsyncSelect");
    	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, TEXT("This program requires Windows NT!"),
    			szAppName, MB_ICONERROR);
    		return 0;
    	}
    	//直接发送WM_CREATE消息
    	hwnd = CreateWindow(szAppName,	// window class name
    		TEXT("WSAAsyncSelect"),			// window caption
    		WS_OVERLAPPEDWINDOW,			// window style
    		CW_USEDEFAULT,					// initial x position
    		CW_USEDEFAULT,					// initial y position
    		CW_USEDEFAULT,					// initial x size
    		CW_USEDEFAULT,					// initial y size
    		NULL,							// parent window handle
    		NULL,							// window menu handle
    		hInstance,						// program instance handle
    		NULL);							// creation parameters
    	//到此,窗口在内存已经存在
    	ShowWindow(hwnd, iCmdShow);
    	UpdateWindow(hwnd);
    
    	//-----------Socket------------
    	WSADATA		wsaData;
    	SOCKET		sServer;
    
    	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    	{
    		return -1;
    	}
    
    	sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    	if (sServer == INVALID_SOCKET)
    	{
    		return -1;
    	}
    
    	SOCKADDR_IN addrServ;
    	addrServ.sin_family = AF_INET;
    	addrServ.sin_port = htons(9999);
    	addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    	if (bind(sServer, (const struct sockaddr*)&addrServ, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
    	{
    		return -1;
    	}
    	
    	if (listen(sServer, 5) == SOCKET_ERROR)
    	{
    		return -1;
    	}
    
    	WSAAsyncSelect(sServer, hwnd, WM_SOCKET, FD_ACCEPT | FD_CLOSE);
    
    
    
    	while (GetMessage(&msg, NULL, 0, 0))
    	{
    		TranslateMessage(&msg);//键盘消息转换
    		DispatchMessage(&msg);//把消息返回操作系统,系统callback
    	}
    	closesocket(sServer);
    	WSACleanup();
    	return msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) //回调函数,操作系统调用
    {
    	HDC					hdc;
    	PAINTSTRUCT			ps;
    	static char			buf[MAXDATASIZE], temp[MAXDATASIZE];
    	static char			szDateTime[50];
    	SOCKET				sClient;
    	SYSTEMTIME			st;
    	static SOCKADDR_IN	addrClient;
    
    
    	switch (message)
    	{
    	case WM_CREATE://可以进行动态链接库dll的载入
    		return 0;
    
    	case WM_PAINT:
    		hdc = BeginPaint(hwnd, &ps);
    		TextOutA(hdc, 0, 0, buf, strlen(buf));
    		EndPaint(hwnd, &ps);
    		return 0;
    
    	case WM_SOCKET:
    	{
    		if (WSAGETSELECTERROR(lParam))
    		{
    			closesocket(wParam);
    			return -1;
    		}
    		switch (WSAGETSELECTEVENT(lParam))
    		{
    		case FD_ACCEPT:
    			if ((sClient = accept(wParam, (struct sockaddr *)&addrClient, NULL)) == INVALID_SOCKET)
    			{
    				closesocket(sClient);
    				break;
    			}
    			//MessageBoxA(NULL, inet_ntoa(addrClient.sin_addr), "IP", 0);
    			WSAAsyncSelect(sClient, hwnd, WM_SOCKET, FD_READ | FD_WRITE | FD_CLOSE);
    			break;
    		case FD_READ:
    			GetLocalTime(&st);
    			memset(szDateTime, 0, sizeof(szDateTime));
    			sprintf(szDateTime, "%4d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
    				st.wHour, st.wMinute, st.wSecond);
    
    			memset(temp, 0, sizeof(temp));
    			if (recv(wParam, temp, MAXDATASIZE, 0) == SOCKET_ERROR)
    			{
    				return -1;
    			}
    			//sprintf(buf, "%s, Recv From Client [%s:%d] :%s
    ", szDateTime, inet_ntoa(addrClient.sin_addr), addrClient.sin_port, temp);
    
    			sprintf(buf, "%s, Recv From Client:%s
    ", szDateTime, temp);
    
    			if (send(wParam, temp, strlen(temp), 0) == SOCKET_ERROR)
    			{
    				return -1;
    			}
    			InvalidateRect(hwnd, NULL, TRUE);
    			UpdateWindow(hwnd);
    			break;
    		case FD_CLOSE:
    			closesocket(wParam);
    			break;
    		}
    		return 0;
    	}
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		return 0;
    	}
    	return DefWindowProc(hwnd, message, wParam, lParam);//默认系统消息处理
    }


    Keep it simple!
    作者:N3verL4nd
    知识共享,欢迎转载。
  • 相关阅读:
    Linux系统的tomcat以daemon模式启动并配置成服务202004
    HBuilder android 开发者证书的生成20200416
    【office相关问题】Excel无法打开文件xxx.xlsx,因为文件格式或文件扩展名无效。请确定文件未损坏解决办法
    RHEL6.4服务器整体迁移记录RHEL6.9-2020-操作系统安装在M2固态,应用/数据库重要数据安装至DELL-H310阵列卡RAID1上保证数据安全性
    Linux下将自己安装的Apache(httpd)新增为系统服务,开机自启动
    Linux安装mysql(解压版)tar包解压安装(靠谱版)
    koa2实现jwt登录
    详解js数组扁平化
    快速掌握ES6 iterator Generator和async 之间的关系及其用法
    快速掌握ES6的class用法
  • 原文地址:https://www.cnblogs.com/lgh1992314/p/6616385.html
Copyright © 2011-2022 走看看