【Windows网络编程】EventSelect网络模型

来源:互联网 发布:linux增加分辨率 编辑:程序博客网 时间:2024/05/16 09:28
//解决select模型工作者线程时间片未充分利用的问题#include <winsock2.h>#include <stdio.h>#define PORT 6000#pragma comment (lib,"Ws2_32.lib")SOCKET ArrSocket[1024] = { 0 };WSAEVENT ArrEvent[1024] = { 0 };DWORD dwTotal = 0;DWORD dwIndex = 0;int ClientNums = 0;         //标记已经链接了多少个客户端BOOL WinSockInit(){WSADATA data = { 0 };if (WSAStartup(MAKEWORD(2, 2), &data))return FALSE;if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2){WSACleanup();return FALSE;}return TRUE;}//工作者线程 怎么实现 将监听的socket以及客户端通信的socket 同时进行监控?//怎么来节省时间的?(相对select)DWORD WINAPI ListentThreadProc(LPARAM lparam){char buf[1024] = { 0 };SOCKET sockClient = INVALID_SOCKET;  //用于accept临时使用的socketWSANETWORKEVENTS NetWorkEvent = { 0 };while (true){//ArrSocket[1];//数组内任意一个wsaevent有信号了,api就返回。。dwIndex = WSAWaitForMultipleEvents(dwTotal, ArrEvent, FALSE, 100, FALSE);if (dwIndex == WSA_WAIT_TIMEOUT){continue;}//如何知道是哪个socket出现了网络事件,deindex发生网络事件的socket数组下标WSAEnumNetworkEvents(ArrSocket[dwIndex - WSA_WAIT_EVENT_0], ArrEvent[dwIndex - WSA_WAIT_EVENT_0], &NetWorkEvent);if (NetWorkEvent.lNetworkEvents&FD_ACCEPT){//如果第三位数据是1,代表有客户端进行连接if (NetWorkEvent.iErrorCode[FD_ACCEPT_BIT] != 0){continue;}sockClient = accept(ArrSocket[dwIndex - WSA_WAIT_EVENT_0], NULL, NULL);if (sockClient == INVALID_SOCKET)continue;//连接完成后,立即将客户端的socket保存到数据,同时新建event与socket建立关系WSAEVENT newEvent = WSACreateEvent();WSAEventSelect(sockClient, newEvent, FD_READ | FD_WRITE | FD_CLOSE);for (;;);//检查数组内是否有空值,如果有就保存。。ArrSocket[dwTotal] = sockClient;ArrEvent[dwTotal] = newEvent;++dwTotal;++ClientNums;}if (NetWorkEvent.lNetworkEvents&FD_READ)    //说明有客户端向服务器发送数据 但这个数据还只在网卡上 没有到达程序buffer{if (NetWorkEvent.iErrorCode[FD_READ_BIT] != 0){continue;}recv(ArrSocket[dwIndex - WSA_WAIT_EVENT_0], buf, sizeof(buf), 0);printf("Recv:%s\n", buf);send(ArrSocket[dwIndex - WSA_WAIT_EVENT_0], buf, strlen(buf), 0);}if (NetWorkEvent.lNetworkEvents&FD_WRITE)   //说明程序-服务器准备向客户端发送信息了、、{if (NetWorkEvent.iErrorCode[FD_WRITE_BIT] != 0){continue;}printf("Send somthing\n");}if (NetWorkEvent.lNetworkEvents&FD_CLOSE)   //表示有一个socket关闭了 是监听的还是通信的 不需要关心。。{if (NetWorkEvent.iErrorCode[FD_CLOSE_BIT] != 0){continue;}closesocket(ArrSocket[dwIndex - WSA_WAIT_EVENT_0]);ArrSocket[dwIndex - WSA_WAIT_EVENT_0] = 0;}}}int main(){WinSockInit();SOCKET sockListen = INVALID_SOCKET;//服务器监听的socketsockListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (sockListen == INVALID_SOCKET){printf("Creat Socket Error");return -1;}sockaddr_in service;service.sin_family = AF_INET;service.sin_addr.S_un.S_addr = INADDR_ANY;service.sin_port = htons(PORT);if (bind(sockListen, (sockaddr*)&service, sizeof(service)) == SOCKET_ERROR){printf("Bind Failed\n");return -1;}//进行event select特有的操作WSAEVENT ListenEvent = WSACreateEvent();//把WSAEVENT与一个socket进行绑定没 告诉绑定的对象需要关注的事件有哪些WSAEventSelect(sockListen, ListenEvent, FD_ACCEPT | FD_CLOSE);//仅关注两个事件,有客户端进行连接,需要关闭服务器监听的socketCreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ListentThreadProc, NULL, NULL, NULL);//创建一个子进程,用子进程来处理所有的socket上的事件if (listen(sockListen, SOMAXCONN) == SOCKET_ERROR){printf("Listen Error\n");return -1;}ArrSocket[dwTotal] = sockListen;ArrEvent[dwTotal] = ListenEvent;++dwTotal;//标识总共有多少个用户已经连接 到这里数组保存的socket只有一个system("pause");if (sockListen != INVALID_SOCKET){closesocket(sockListen);}WSACleanup();return 0;}