您的位置:首页 > 理论基础 > 计算机网络

基于WSAEventSelect模型的TCP服务器实现

2009-04-10 17:24 656 查看
怎么感觉标题很学术的样子。。。上次那个重叠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
<< " ";
}
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: