工作原理流程大致是这样:
- 定义一个socket数组和event数组
- 每一个socket操作关联一个event对象
- 调用WSAWaitForMultipleEvents函数等待事件的触发
- 调用WSAEnumNetworkEvents函数查看是哪个一个事件,根据事件找到相应的socket,然后进行相应的处理:比如数据显示等,同时,记得要将那个event重置为无信号状态 。
- 循环步骤3和4,直到服务器退出 。流程图
文章插图
UINT CMFCWSAEventDlg::ThreadProc(LPVOID lparam) { // TODO: 在此添加控件通知处理程序代码 CMFCWSAEventDlg* p = (CMFCWSAEventDlg*)lparam; SocketInit socketInit; SOCKET socketServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (socketServer == INVALID_SOCKET) {AfxMessageBox(_T("套接字创建失败"));closesocket(socketServer);WSACleanup(); } sockaddr_in sock; sock.sin_family = AF_INET; sock.sin_port = htons(5678); sock.sin_addr.S_un.S_addr = INADDR_ANY; int n = sizeof(sock); if (bind(socketServer, (sockaddr*)&sock, sizeof(sock)) == SOCKET_ERROR) {AfxMessageBox(_T("监听失败"));closesocket(socketServer);WSACleanup(); } if (listen(socketServer, SOMAXCONN) == SOCKET_ERROR) {AfxMessageBox(_T("监听失败"));closesocket(socketServer);WSACleanup(); } p->showText.SetWindowText("开始监听\r\n"); // 创建事件对象,并关联到新的套节字 WSAEVENT event = ::WSACreateEvent(); ::WSAEventSelect(socketServer, event, FD_ACCEPT | FD_CLOSE); // 添加到表中 p->eventArray[p->nEventTotal] = event; p->sockArray[p->nEventTotal] = socketServer; p->nEventTotal++; CString str; sockaddr_in addrRemote; while (1){// 在所有事件对象上等待int nIndex = ::WSAWaitForMultipleEvents(p->nEventTotal, p->eventArray, FALSE, WSA_INFINITE, FALSE);// 对每个事件调用WSAWaitForMultipleEvents函数,以便确定它的状态nIndex = nIndex - WSA_WAIT_EVENT_0;for (int i = nIndex; i < p->nEventTotal; i++){nIndex = ::WSAWaitForMultipleEvents(1, &p->eventArray[i], TRUE, 1000, FALSE);if (nIndex == WSA_WAIT_FAILED || nIndex == WSA_WAIT_TIMEOUT){continue;}else{// 获取到来的通知消息,WSAEnumNetworkEvents函数会自动重置受信事件WSANETWORKEVENTS event;::WSAEnumNetworkEvents(p->sockArray[i], p->eventArray[i], &event);if (event.lNetworkEvents & FD_ACCEPT) // 处理FD_ACCEPT通知消息{if (event.iErrorCode[FD_ACCEPT_BIT] == 0){if (p->nEventTotal > WSA_MAXIMUM_WAIT_EVENTS){p->showText.SetSel(-1);p->showText.ReplaceSel("时间太长");continue;}int nAddrLen = sizeof(addrRemote);SOCKET sNew = ::accept(p->sockArray[i], (SOCKADDR*)&addrRemote, &nAddrLen);//MessageBox("已连接");int nLen = p->showText.GetWindowTextLengthA();//p->showText.SetWindowText()str.Format("%s建立连接\r\n", ::inet_ntoa(addrRemote.sin_addr));p->showText.SetSel(-1);p->showText.ReplaceSel(str);WSAEVENT event = ::WSACreateEvent();::WSAEventSelect(sNew, event, FD_READ | FD_CLOSE | FD_WRITE);// 添加到表中p->eventArray[p->nEventTotal] = event;p->sockArray[p->nEventTotal] = sNew;p->nEventTotal++;}}else if (event.lNetworkEvents & FD_READ) // 处理FD_READ通知消息{if (event.iErrorCode[FD_READ_BIT] == 0){//char szText[256];char szText[1024] = { 0 };//memset(szText, 0, sizeof(szText));int nlen = strlen(szText);int nRecv = ::recv(p->sockArray[i], szText,1024, 0);//AfxMessageBox(nRecv);if (nRecv > 0){szText[nRecv] = '\0';str.Format("%s发来了一条消息:%s\r\n", ::inet_ntoa(addrRemote.sin_addr), szText);p->showText.SetSel(-1);p->showText.ReplaceSel(str);//szText[0] = '\0';// 向客户端发送数据char *sendText = getallprime(1000);if (::send(p->sockArray[i], sendText, strlen(sendText), 0) > 0){p->showText.SetSel(-1);p->showText.ReplaceSel("已发送结果\r\n");}}}}else if (event.lNetworkEvents & FD_CLOSE) // 处理FD_CLOSE通知消息{if (event.iErrorCode[FD_CLOSE_BIT] == 0){::closesocket(p->sockArray[i]);for (int j = i; j < p->nEventTotal - 1; j++){p->eventArray[j] = p->eventArray[j + 1];p->sockArray[j] = p->sockArray[j + 1];}p->nEventTotal--;}p->showText.SetSel(-1);p->showText.ReplaceSel("关闭连接\r\n");}}} }}
推荐阅读
- 33 《吐血整理》高级系列教程-吃透Fiddler抓包教程-Fiddler如何抓取WebSocket数据包
- Websocket集群解决方案
- 半自动版本 PXE批量装windows
- Windows操作系统搭建Lsky Pro
- 关于ASP.NET Core WebSocket实现集群的思考
- Spark简单介绍,Windows下安装Scala+Hadoop+Spark运行环境,集成到IDEA中
- Windows 环境搭建 PostgreSQL 物理复制高可用架构数据库服务
- MongoDB数据库新手入门
- Windows下自动云备份思源笔记到Gitee
- windows启动不了开不了机怎么办(笔记本无法启动windows)