怎么感觉标题很学术的样子。。。上次那个重叠IO的事件模型搞完之后,就觉得TCP是很不错的协议,可以将重点转移到对客户端的管理之上,而不必为了数据报的丢失和客户端keepalive的问题而绞尽脑汁(之前我做了个简单的聊天软件,面对的就是这种问题)。 WSAEventSelect是基于事件通知的,我觉得没有比这个模型更加简单实用了,编译环境:vc++ 6.0,代码如下:
#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; }
发表于 @ 2009年04月10日 17:24:00 | 评论( loading... ) | 编辑| 举报| 收藏