![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.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;
}