Windows C++运用IOCP IO多路复用同时监听1000个tcp套接字消息

Windows C++运用IOCP IO多路复用同时监听1000个tcp套接字消息

  1. 建立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传输协议

  1. 断开连接
BOOL CSendInfoToServer::CloseConnection(SOCKET socket)
{

	if (socket != INVALID_SOCKET)
	{
		closesocket(socket);
		socket = INVALID_SOCKET;
	}
	return TRUE;
}
  1. 创建接收对象类
struct client
{
	SOCKET m_Socket;

	//用于IOCP接收心跳消息
	WSABUF dataBuffer;
	OVERLAPPED overlapped;
	char receivedData[4096]; //这个空间一定要足够大,足以去存放接收到一次数据
}
  1. 接收到数据的消息的处理线程
// 任务函数回调
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;
		}
	}
}
  1. 主函数
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();*/
			}
		}
}
  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值