基于WSAEventSelect异步 I / O模型的TCP/IP流式套接字服务器具体实现主要分为下面两个步骤。
1 首先创建流式套接字。代码如下:
WSAData ws;
sockaddr_in addr;
WSAStartup(MAKEWORD(2, 2), &ws);
SOCKET svrsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
addr.sin_family = PF_INET;
addr.sin_addr.s_addr = inet_addr(SetInfor->sIp.c_str()); // 服务器IP转网络字节序
addr.sin_port = htons(SetInfor->nPort); // 服务器端口转网络字节
// 绑定套接字
int nError = bind(svrsock, (sockaddr*)&addr, sizeof(addr));
WSAEVENT newEvent = WSACreateEvent();
WSAEventSelect(svrsock, newEvent, FD_ACCEPT | FD_CLOSE); // 只监听读和关闭
// 监听套接字
listen(svrsock, 5);
m_sockets[m_nTotal] = svrsock;
m_events[m_nTotal] = newEvent;
++m_nTotal;
m_CHThread.Start(); // 开启线程以便访问流式套接字的网络事件方法
2 在线程函数中遍历套接字的网络事件方法,主要代码如下:
WSANETWORKEVENTS networkevent;
while (!m_bExit)
{
#if 0
OutputDebugString(L"run!\n");
#endif
CAutoLock autolock(&m_myLock);
DWORD drindex = WSAWaitForMultipleEvents(m_nTotal, m_events, FALSE, 100, FALSE);//WSA_INFINITE
// 加锁
if (WSA_WAIT_TIMEOUT == drindex)
{
continue;
}
// 有网络事件
WSAEnumNetworkEvents(
m_sockets[drindex - WSA_WAIT_EVENT_0],
m_events[drindex - WSA_WAIT_EVENT_0], // 自动重置未传信状态
&networkevent);
if (networkevent.lNetworkEvents & FD_ACCEPT)
{
if (networkevent.iErrorCode[FD_ACCEPT_BIT] != 0)
{
char msg[100] = { 0 };
sprintf_s(msg, 100, "FD_CONNECT Failed with error %d \n", networkevent.iErrorCode[FD_ACCEPT_BIT]);
printf(msg);
if (m_pTcpSvrNotifyInf)
{
m_pTcpSvrNotifyInf->onAccept(-1);
for (int i = 0; i < m_nTotal; i++)
{
closesocket(m_sockets[i]);
WSACloseEvent(m_events[i]);
}
m_nTotal = 0;
m_CHThread.suspend(); // 暂停线程
}
continue;
}
sockaddr_in addr;
int naddrLen = sizeof(addr); // 必须要赋实际值,不能为0,为0的话accept返回的socket就会有问题
char msg[100] = { 0 };
#if 1
SOCKET clisocket = accept(m_sockets[drindex - WSA_WAIT_EVENT_0], (PSOCKADDR)&addr, &naddrLen);
string ip = inet_ntoa(addr.sin_addr);
unsigned short port = ntohs(addr.sin_port);
sprintf_s(msg, 100, "客户端信息: %s:%d \n", (char*)ip.c_str(), port);
OutputDebugStringA(msg);
#else
SOCKET clisocket = accept(m_sockets[drindex - WSA_WAIT_EVENT_0], NULL, NULL);
#endif
if (m_nTotal >= WSA_MAXIMUM_WAIT_EVENTS)
{
sprintf_s(msg,100,"超过了最大的连接数64\n");
OutputDebugStringA(msg);
closesocket(clisocket);
break;
}
WSAEVENT newEvent = WSACreateEvent();
WSAEventSelect(clisocket, newEvent, FD_READ | FD_WRITE | FD_CLOSE); // 只监听读、写、关闭
m_sockets[m_nTotal] = clisocket;
m_events[m_nTotal] = newEvent;
m_nTotal++;
sprintf_s(msg, 100, "clisocket %d connected!\n", clisocket);
OutputDebugStringA(msg);
if (m_pTcpSvrNotifyInf)
{
m_pTcpSvrNotifyInf->onAccept(0);
}
}
else if (networkevent.lNetworkEvents & FD_READ)
{
if (networkevent.iErrorCode[FD_READ_BIT] != 0)
{
char msg[100] = { 0 };
sprintf_s(msg, 100, "FD_READ Failed with error %d \n", networkevent.iErrorCode[FD_READ_BIT]);
printf(msg);
OutputDebugStringA(msg);
for (int i = 0; i < m_nTotal; i++)
{
closesocket(m_sockets[i]);
WSACloseEvent(m_events[i]);
}
m_nTotal = 0;
m_CHThread.suspend(); // 暂停线程
continue;
}
char buf[4096] = { 0 };
int nLen = recv(m_sockets[drindex - WSA_WAIT_EVENT_0], buf, 4096, 0);
printf("收到的数据为:%s \n", buf);
char msg[100] = { 0 };
sprintf_s(msg, 100, "收到的数据为:%s nDataLen:%d \n", (char*)buf, nLen);
string strmsg = msg;
wstring wstrmsg;
CCharactor::StringToWString(strmsg, wstrmsg);
OutputDebugString(wstrmsg.c_str());
string msgData = buf;
string::size_type index = msgData.find(',');
if (index != string::npos)
{
string strtempfile = msgData.substr(index + 1, msgData.length() - index);
if (m_curtempfile.empty())
{
m_curtempfile = strtempfile;
}
else
{
if (0 == m_curtempfile.compare(strtempfile.c_str()))
{
char msg[200] = { 0 };
sprintf_s(msg, 200, "较上次收到的文件一致,直接退出(文件名:%s.ezd)", m_curtempfile.c_str());
unsigned char OkMsg[10] = { 0 };
sprintf_s((char*)OkMsg, 10, "randy");
send(m_sockets[drindex - WSA_WAIT_EVENT_0], (char*)OkMsg, strlen((char*)OkMsg), 0);
continue;
}
else
{
m_curtempfile = strtempfile;
}
}
}
wstring wstr;
CCharactor::StringToWString(m_curtempfile, wstr);
CString cstr = wstr.c_str();
if (m_pTcpSvrNotifyInf)
{
m_pTcpSvrNotifyInf->onUpdateData(cstr);
}
}
else if (networkevent.lNetworkEvents & FD_WRITE)
{
OutputDebugStringA("可以开始发送数据了\n");
}
else if (networkevent.lNetworkEvents & FD_CLOSE)
{
if (networkevent.iErrorCode[FD_CLOSE_BIT] != 0)
{
char msg[100] = { 0 };
sprintf_s(msg, 100, "FD_CLOSE Failed with error %d \n", networkevent.iErrorCode[FD_CLOSE_BIT]);
printf(msg);
OutputDebugStringA(msg);
for (int i = 0; i < m_nTotal; i++)
{
closesocket(m_sockets[i]);
WSACloseEvent(m_events[i]);
}
m_nTotal = 0;
m_CHThread.suspend(); // 暂停线程
break;
}
char msg[100] = { 0 };
sprintf_s(msg, 100, "socket %d closed! index:%d\n", m_sockets[drindex - WSA_WAIT_EVENT_0], drindex - WSA_WAIT_EVENT_0);
closesocket(m_sockets[drindex - WSA_WAIT_EVENT_0]);
// 后面的往前移
for (int i = drindex - WSA_WAIT_EVENT_0; i < m_nTotal-1; i++)
{
m_sockets[i] = m_sockets[i + 1];
}
m_nTotal--;
printf(msg);
OutputDebugStringA(msg);
if (m_pTcpSvrNotifyInf)
m_pTcpSvrNotifyInf->onClientClosed();
}
}