WSAevent
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// TODO: 在此添加控件通知处理程序代码 CString str,edit_str; GetDlgItemText(IDC_StartServer, str); // 事件句柄和套节字句柄表 WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS]; SOCKET sockArray[WSA_MAXIMUM_WAIT_EVENTS]; int nEventTotal = 0; if (str=="开始") { SetDlgItemText(IDC_StartServer,_T("停止")); // 创建监听套节字 /* Enable address reuse */ int ret; char on; on = 1; USHORT nPort = 4567; // 此服务器监听的端口号 SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ret = setsockopt( sListen, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ); sockaddr_in sin; memset( &sin, 0, sizeof(sin) ); sin.sin_family = AF_INET; sin.sin_port = htons(nPort); sin.sin_addr.S_un.S_addr = INADDR_ANY; if(::bind(sListen, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR) { edit_str= " Failed bind()"; // ::AfxMessageBox(_T("Failed bind")); GetDlgItem(IDC_EDIT3)->SetWindowText(edit_str); } else { //::AfxMessageBox(_T("bind success")); GetDlgItem(IDC_EDIT3)->SetWindowText(_T("bind success!")); } ::listen(sListen, 5); // 创建事件对象,并关联到新的套节字 WSAEVENT event = ::WSACreateEvent(); ::WSAEventSelect(sListen, event, FD_ACCEPT|FD_CLOSE); // 添加到表中 eventArray[nEventTotal] = event; sockArray[nEventTotal] = sListen; nEventTotal++; // 处理网络事件 while(TRUE) { // 在所有事件对象上等待 int nIndex = ::WSAWaitForMultipleEvents(nEventTotal, eventArray, FALSE, WSA_INFINITE, FALSE); // 对每个事件调用WSAWaitForMultipleEvents函数,以便确定它的状态 nIndex = nIndex - WSA_WAIT_EVENT_0;//发生的事件对象的索引,一般是句柄数组中最前面的那一个,然后再用循环依次处理后面的事件对象 for(int i=nIndex; i<nEventTotal; i++) { int ret; ret = ::WSAWaitForMultipleEvents(1, &eventArray[i], TRUE, 1000, FALSE); if(ret == WSA_WAIT_FAILED || ret == WSA_WAIT_TIMEOUT) { continue; } else { // 获取到来的通知消息,WSAEnumNetworkEvents函数会自动重置受信事件 WSANETWORKEVENTS event; ::WSAEnumNetworkEvents(sockArray[i], eventArray[i], &event); if(event.lNetworkEvents & FD_ACCEPT) // 处理FD_ACCEPT通知消息 { if(event.iErrorCode[FD_ACCEPT_BIT] == 0) { if(nEventTotal > WSA_MAXIMUM_WAIT_EVENTS) { GetDlgItem(IDC_EDIT1)->SetWindowText(_T(" Too many connections!")); // printf(" Too many connections! /n"); continue; } SOCKET sNew = ::accept(sockArray[i], NULL, NULL); WSAEVENT event = ::WSACreateEvent(); ::WSAEventSelect(sNew, event, FD_READ|FD_CLOSE|FD_WRITE); // 添加到表中 eventArray[nEventTotal] = event; sockArray[nEventTotal] = sNew; nEventTotal++; } } else if(event.lNetworkEvents & FD_READ) // 处理FD_READ通知消息 { if(event.iErrorCode[FD_READ_BIT] == 0) { char szText[1024]; int nRecv = ::recv(sockArray[i], szText, strlen(szText), 0); if(nRecv > 0) { MessageBox(LPCTSTR(szText)); szText[nRecv] = '\0'; } } } else if(event.lNetworkEvents & FD_CLOSE) // 处理FD_CLOSE通知消息 { if(event.iErrorCode[FD_CLOSE_BIT] == 0) { ::closesocket(sockArray[i]); for(int j=i; j<nEventTotal-1; j++) { sockArray[j] = sockArray[j+1]; sockArray[j] = sockArray[j+1]; } nEventTotal--; } } else if(event.lNetworkEvents & FD_WRITE) // 处理FD_WRITE通知消息 { } } } } } else { SetDlgItemText(IDC_StartServer,_T("开始")); }
#include <tchar.h> #include <iostream> #include <algorithm> #include <winsock2.h> #include <crtdbg.h> #include <cstring> #include <iomanip> #include <list> #pragma comment(lib, "ws2_32.lib") using namespace std; #define LOC_PORT 5678 #define LOC_ADDR "127.0.0.1" class CSocketObject { public: CSocketObject(){WSAStartup(MAKEWORD(2,2), &m_wsaData);} virtual ~CSocketObject(){WSACleanup();} public: virtual void Run() = 0; protected: WSADATA m_wsaData; }; class CTcpServer : public CSocketObject { public: virtual void Run(); private: typedef struct { WSAEVENT event; SOCKET sock; }EVENT_T; list<EVENT_T> m_listClient; static WSAEVENT& DoGetEvent(EVENT_T& ev){return ev.event;} }; void CTcpServer::Run() { SOCKET tSock = socket(AF_INET, SOCK_STREAM, 0); char cBuf[1024]; SOCKADDR_IN tAddr, tComeinAddr; tAddr.sin_family = AF_INET; tAddr.sin_port = htons(LOC_PORT); tAddr.sin_addr.s_addr = inet_addr(LOC_ADDR); _ASSERT(bind(tSock,(SOCKADDR*)&tAddr, sizeof(tAddr)) == 0); WSAEVENT hWSAEvent = WSACreateEvent(); WSAEventSelect(tSock, hWSAEvent, FD_ACCEPT); _ASSERT(listen(tSock, 5) == 0); EVENT_T ev = {hWSAEvent, tSock}; m_listClient.push_back(ev); WSAEVENT events[64]; for (;;) { transform(m_listClient.begin(), m_listClient.end(), events, DoGetEvent); int dwIndex = WSAWaitForMultipleEvents(m_listClient.size(), events, false, WSA_INFINITE, false); list<EVENT_T>::iterator iter = m_listClient.begin(); int iPos = 0; while (iPos++ != dwIndex - WSA_WAIT_EVENT_0)++iter; WSANETWORKEVENTS tNetEvents; WSAEnumNetworkEvents(iter->sock, iter->event, &tNetEvents); if (FD_ACCEPT & tNetEvents.lNetworkEvents) { if (0 != tNetEvents.iErrorCode[FD_ACCEPT_BIT]) { std::cout<<"accept error occured/n"; continue; } else { int dwAddrLen = sizeof(tComeinAddr); SOCKET tSockIn = accept(tSock, (sockaddr*)&tComeinAddr, &dwAddrLen); ev.event = WSACreateEvent(); WSAEventSelect(tSockIn, ev.event, FD_READ | FD_CLOSE); ev.sock = tSockIn; m_listClient.push_back(ev); cout << "new come in..." << inet_ntoa(tComeinAddr.sin_addr) << "/n"; send(tSockIn, "You are welcome", strlen("You are welcome"), 0); } } else if (FD_READ & tNetEvents.lNetworkEvents) { if (0 != tNetEvents.iErrorCode[FD_READ_BIT]) { std::cout<<"read error occured/n"; continue; } else { int dwRet = recv(iter->sock, cBuf, 1024, 0); if (SOCKET_ERROR == dwRet) { } else { cout << "client...data: "; for (int n = 0; n != dwRet; ++n) { cout << "0x" << hex << (int)cBuf[n] << " "; } cout << endl; } } } else if (FD_CLOSE & tNetEvents.lNetworkEvents) { int dwNameLen = sizeof(tComeinAddr); getpeername(iter->sock, (sockaddr*)&tComeinAddr, &dwNameLen); closesocket(iter->sock); WSACloseEvent(iter->event); m_listClient.erase(iter); cout << "client..." << inet_ntoa(tComeinAddr.sin_addr) << " quit/n"; } } } int _tmain(int argc, TCHAR *argv[]) { CSocketObject *poSockServer = new CTcpServer; poSockServer->Run(); delete poSockServer; return 0; }