哎,如此多要学习的

来源:互联网 发布:判断端口是否被拦截 编辑:程序博客网 时间:2024/05/01 00:42
#include <winsock.h>#include <tchar.h>#define PORT      5000#define MSGSIZE   1024#define WM_SOCKET WM_USER+0    #pragma comment(lib, "ws2_32.lib")LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){static TCHAR szAppName[] = _T("AsyncSelect Model");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 ;}hwnd = CreateWindow (szAppName,                  // window class nameTEXT ("AsyncSelect Model"), // window captionWS_OVERLAPPEDWINDOW,        // window styleCW_USEDEFAULT,              // initial x positionCW_USEDEFAULT,              // initial y positionCW_USEDEFAULT,              // initial x sizeCW_USEDEFAULT,              // initial y sizeNULL,                       // parent window handleNULL,                       // window menu handlehInstance,                  // program instance handleNULL) ;                     // creation parametersShowWindow(hwnd, iCmdShow);UpdateWindow(hwnd);while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg) ;DispatchMessage(&msg) ;}return msg.wParam;}LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){WSADATA       wsd;static SOCKET sListen;SOCKET        sClient;SOCKADDR_IN   local, client;int           ret, iAddrSize = sizeof(client);char          szMessage[MSGSIZE];switch (message){case WM_CREATE://初始化Socket库WSAStartup(0x0202, &wsd);// 创建监听的socketsListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);// 绑定socketlocal.sin_addr.S_un.S_addr = inet_addr("192.168.1.100");local.sin_family = AF_INET;local.sin_port = htons(PORT); //指定监听端口bind(sListen, (struct sockaddr *)&local, sizeof(local));// 监听listen(sListen, 3);// 注册监听socket FD_ACCEPT事件,当 监听socket 有客户连接时,会发送窗口消息WM_SOCKET给本窗口WSAAsyncSelect(sListen, hwnd, WM_SOCKET, FD_ACCEPT);return 0;case WM_DESTROY:closesocket(sListen);WSACleanup();PostQuitMessage(0);return 0;case WM_SOCKET:if (WSAGETSELECTERROR(lParam)){closesocket(wParam);break;}switch (WSAGETSELECTEVENT(lParam)) //分析WM_SOCKET的消息类型{case FD_ACCEPT:// 接受一个客户连接sClient = accept(wParam, (struct sockaddr *)&client, &iAddrSize);MessageBox(hwnd,"客户接入事件",NULL,NULL);// 注册客户socket FD_READ 和 FD_CLOSE 事件WSAAsyncSelect(sClient, hwnd, WM_SOCKET, FD_READ | FD_CLOSE);break;case FD_READ:ret = recv(wParam, szMessage, MSGSIZE, 0);MessageBox(hwnd,"读取事件",NULL,NULL);if (ret == 0 || ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET){closesocket(wParam);}else{szMessage[ret] = '\0';send(wParam, szMessage, strlen(szMessage), 0);}break;case FD_CLOSE:MessageBox(hwnd,"关闭事件",NULL,NULL);closesocket(wParam);      break;default:   //默认消息,也可以认为socket断开.closesocket(wParam);      break;}return 0;}return DefWindowProc(hwnd, message, wParam, lParam);}



在我看来,WSAAsyncSelect是最简单的一种Winsock I/O模型(之所以说它简单是因为一个主线程就搞定了)。使用Raw Windows API写过窗口类应用程序的人应该都能看得懂。这里,我们需要做的仅仅是:1.在WM_CREATE消息处理函数中,初始化Windows Socket library,创建监听套接字,绑定,监听,并且调用WSAAsyncSelect函数表示我们关心在监听套接字上发生的FD_ACCEPT事件;2.自定义一个消息WM_SOCKET,一旦在我们所关心的套接字(监听套接字和客户端套接字)上发生了某个事件,系统就会调用WndProc并且message参数被设置为WM_SOCKET;3.在WM_SOCKET的消息处理函数中,分别对FD_ACCEPT、FD_READ和FD_CLOSE事件进行处理;4.在窗口销毁消息(WM_DESTROY)的处理函数中,我们关闭监听套接字,清除Windows Socket library下面这张用于WSAAsyncSelect函数的网络事件类型表可以让你对各个网络事件有更清楚的认识:表1FD_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  应用程序想接收针对套接字的协议家族,本地地址列表发生变化的通知