Windows C++运用IOCP IO多路复用同时监听1000个tcp套接字消息
- 建立TCP连接
BOOL CreateConnection(SOCKET socket, CString strServerIP,const CString strServerPort)
{
//创建socket
socket = socket(AF_INET, SOCK_STREAM, 0);
if(socket == INVALID_SOCKET)
{
WriteError(_T("socket() called failed!"));
return -1;
}
unsigned long ul = 1;
// 设置socket选项等操作...
SOCKADDR_IN addrServer;
addrServer.sin_addr.S_un.S_addr = inet_addr(wchar2char(strServerIP.GetBuffer()));
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(_ttoi(strServerPort));
int nRes=-1;
if (connect(socket, (sockaddr*)&addrServer, sizeof(addrServer)) == SOCKET_ERROR)
{
WriteError(_T("Failed to connect to server"));
closesocket(socket);
return nRes;
}
nRes=true;
return nRes;
}
其中socket()方法为:
参数一:domain(协议域):指定协议使用的地址族,常见的值有:
AF_INET:IPv4地址族
AF_INET6:IPv6地址族
AF_UNIX:Unix套接字
参数二:type(套接字类型):指定套接字的类型,常见的值有:
SOCK_STREAM:面向连接的流套接字,使用TCP协议
SOCK_DGRAM:无连接的数据报套接字,使用UDP协议
SOCK_RAW:原始套接字,用于底层网络协议访问
参数三:protocol(协议):指定使用的协议,常见的值有:
IPPROTO_TCP:TCP传输协议
IPPROTO_UDP:UDP传输协议
- 断开连接
BOOL CSendInfoToServer::CloseConnection(SOCKET socket)
{
if (socket != INVALID_SOCKET)
{
closesocket(socket);
socket = INVALID_SOCKET;
}
return TRUE;
}
- 创建接收对象类
struct client
{
SOCKET m_Socket;
//用于IOCP接收心跳消息
WSABUF dataBuffer;
OVERLAPPED overlapped;
char receivedData[4096]; //这个空间一定要足够大,足以去存放接收到一次数据
}
- 接收到数据的消息的处理线程
// 任务函数回调
static VOID CALLBACK TaskFunction(PTP_CALLBACK_INSTANCE instance, LPVOID lpParam, PTP_WORK work)
{
client* pCurClient = static_cast<client*>(lpParam);
//其中pCurClient->receivedData;就是接收到的数据
string strData = pCurClient->receivedData;
std::cout<<strData;
// 提交下一个重叠IO请求
// 创建缓冲区
ZeroMemory(&(pCurClient->overlapped), sizeof(OVERLAPPED));
pCurClient->dataBuffer.len = 4096;
pCurClient->dataBuffer.buf = &(pCurClient->receivedData[0]);
DWORD flags = 0;
if (WSARecv(pCurClient->m_Socket, &(pCurClient->dataBuffer), 1, NULL, &flags, &(pCurClient->overlapped), NULL) == SOCKET_ERROR)
{
int errorCode = WSAGetLastError();
if (errorCode != WSA_IO_PENDING)
{
WriteError(_T("Failed to submit overlapped IO request"));
closesocket(pCurClient->m_tSocket);
return;
}
}
return;
}
5.iocp监听线程,接到消息丢给线程池
//用于接收TCP心跳到来的数据
unsigned int RecvTCPFunc()
{
// 创建IOCP对象
g_iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
//创建线程池,
g_threadPool = CreateThreadpool(NULL);
if (g_threadPool == NULL)
{
MessageBox(0, _T("接收线程池启动失败,重启该应用重新尝试"), _T("错误"), 0);
return 1;
}
// 设置线程池最小线程数和最大线程数
SetThreadpoolThreadMinimum(g_threadPool, 1);
SetThreadpoolThreadMaximum(g_threadPool, 1000);
if (g_iocp == NULL)
{
WriteError(_T("CreateIoCompletionPort error: Failed to create IOCP."));
return 1;
}
DWORD bytesTransferred = 0;
ULONG_PTR completionKey = 0;
LPOVERLAPPED overlapped = NULL;
while (TRUE)
{
// 等待IO完成
if (GetQueuedCompletionStatus(g_iocp, &bytesTransferred, &completionKey, &overlapped, INFINITE) == 0)
{
int iEr = GetLastError();
WriteError(_T("GetQueuedCompletionStatus error: Failed to get completion status.GetLstError=%d."), iEr);
Sleep(5000);
continue;
}
// 检查套接字是否可读
if (bytesTransferred <= 0)
{
continue;
}
// 创建线程池工作对象
client* pCurClient = (client*)completionKey;
PTP_WORK work = CreateThreadpoolWork(TaskFunction, pCurClient, NULL);
if (work == NULL)
{
WriteError(_T("Failed to create thread pool work!"));
continue;
}
// 提交任务给线程池
SubmitThreadpoolWork(work);
if (overlapped != NULL)
{
delete overlapped;
}
}
}
- 主函数
void main()
{
WSADATA g_wsaData;
HANDLE g_iocp = NULL;
PTP_POOL g_threadPool;
// 初始化Winsock库
int startupResult = WSAStartup(MAKEWORD(2, 2), &g_wsaData);
//FD_ZERO(&g_heartBeatReadSet);
//消息接收线程
AfxBeginThread((AFX_THREADPROC)RecvTCPFunc,NULL, THREAD_PRIORITY_TIME_CRITICAL, 0, 0, NULL);
//循环建立TCP连接
for(int i=0; i<1000; i++)
{
client pClient = new client;
pClient->CreateConnection(pClient->m_Socket,_T("127.0.0.1"), _T("8888"));
// 将socket绑定到IOCP
if (CreateIoCompletionPort((HANDLE)pClient->m_Socket, g_iocp, (ULONG_PTR)pClient, 0) == NULL)
{
WriteError(_T("CreateIoCompletionPort ERROR: Failed to bind socket to IOCP"));
}
// 创建缓冲区
pClient->dataBuffer.buf = &(pClient->receivedData[0]);
pClient->dataBuffer.len = 4096;
// 提交重叠IO请求
if (pClient->m_Socket == INVALID_SOCKET)
{
WriteError(_T("SOCKET ERROR"));
}
// 接收服务器消息
ZeroMemory(&(pClient->overlapped), sizeof(OVERLAPPED));
DWORD flags = 0;
if (WSARecv(pClient->m_Socket,
&(pClient->dataBuffer),
1,
NULL,
&flags,
&(pClient->overlapped),
NULL) == SOCKET_ERROR)
{
int errorCode = WSAGetLastError();
if (errorCode != WSA_IO_PENDING)
{
WriteError(_T("Failed to submit overlapped IO request: %d"), errorCode);
closesocket(sockets[i]);
/*CloseHandle(completionPort);
WSACleanup();*/
}
}
}