请给我一个使用C++的IOCP UDP 发送和接收 例子需要多线程简单点
以下是一个简单的使用IOCP实现UDP发送和接收的C++代码:
#include <iostream>
#include <WS2tcpip.h>
#include <WinSock2.h>
#include <Windows.h>
#pragma comment(lib, "Ws2_32.lib")
DWORD WINAPI ReceiverThread(LPVOID lpParameter);
int main()
{
// 初始化Winsock
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
std::cerr << "WSAStartup failed." << std::endl;
return 1;
}
// 创建UDP socket
SOCKET socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (socket_fd == INVALID_SOCKET)
{
std::cerr << "socket creation failed." << std::endl;
WSACleanup();
return 1;
}
// 绑定socket到本地端口
sockaddr_in local_addr;
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = INADDR_ANY;
local_addr.sin_port = htons(1234);
if (bind(socket_fd, (sockaddr*)&local_addr, sizeof(local_addr)) == SOCKET_ERROR)
{
std::cerr << "bind failed." << std::endl;
closesocket(socket_fd);
WSACleanup();
return 1;
}
// 创建IOCP
HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (iocp == NULL)
{
std::cerr << "CreateIoCompletionPort failed." << std::endl;
closesocket(socket_fd);
WSACleanup();
return 1;
}
// 创建接收线程
HANDLE receiver_thread = CreateThread(NULL, 0, ReceiverThread, (LPVOID)socket_fd, 0, NULL);
if (receiver_thread == NULL)
{
std::cerr << "CreateThread failed." << std::endl;
closesocket(socket_fd);
CloseHandle(iocp);
WSACleanup();
return 1;
}
// 发送数据
sockaddr_in remote_addr;
remote_addr.sin_family = AF_INET;
remote_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
remote_addr.sin_port = htons(1234);
char buf[] = "Hello, world!";
int ret = sendto(socket_fd, buf, sizeof(buf), 0, (sockaddr*)&remote_addr, sizeof(remote_addr));
if (ret == SOCKET_ERROR)
{
std::cerr << "sendto failed." << std::endl;
closesocket(socket_fd);
CloseHandle(iocp);
WSACleanup();
return 1;
}
// 等待接收线程退出
WaitForSingleObject(receiver_thread, INFINITE);
// 清理资源
closesocket(socket_fd);
CloseHandle(iocp);
WSACleanup();
return 0;
}
DWORD WINAPI ReceiverThread(LPVOID lpParameter)
{
SOCKET socket_fd = (SOCKET)lpParameter;
// 将socket关联到IOCP上
HANDLE iocp = CreateIoCompletionPort((HANDLE)socket_fd, NULL, 0, 0);
if (iocp == NULL)
{
std::cerr << "CreateIoCompletionPort failed." << std::endl;
return 1;
}
// 接收数据
sockaddr_in remote_addr;
int addrlen = sizeof(remote_addr);
char buf[1024];
DWORD bytes_recv;
OVERLAPPED overlapped;
ZeroMemory(&overlapped, sizeof(overlapped));
while (true)
{
if (WSARecvFrom(socket_fd, buf, sizeof(buf), &bytes_recv, 0, (sockaddr*)&remote_addr, &addrlen, &overlapped, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
std::cerr << "WSARecvFrom failed." << std::endl;
break;
}
}
DWORD bytes_transferred;
ULONG_PTR completion_key;
LPOVERLAPPED lpOverlapped;
if (GetQueuedCompletionStatus(iocp, &bytes_transferred, &completion_key, &lpOverlapped, INFINITE) == 0)
{
std::cerr << "GetQueuedCompletionStatus failed." << std::endl;
break;
}
std::cout << "Received: " << buf << std::endl;
break; // 接收到数据后退出循环
}
return 0;
}
该示例中,主线程和接收线程分别运行在不同的线程中,主线程负责发送数据,接收线程负责接收数据。
在接收线程中,首先将socket关联到IOCP上,然后使用WSARecvFrom函数异步接收数据。如果接收操作没有立即完成,WSARecvFrom函数将返回WSA_IO_PENDING错误码,并将数据接收操作加入到IOCP的队列中等待完成。接收线程使用GetQueuedCompletionStatus函数从IOCP的队列中获取已完成的操作,如果接收操作完成,将打印接收到的数据。
需要注意的是,WSARecvFrom函数的最后一个参数必须是指向OVERLAPPED结构体的指针,用于传递异步操作的参数。在本例中,使用了一个名为overlapped的全局OVERLAPPED结构体来传递参数,每次接收操作都使用该结构体进行参数传递。如果多个异步操作同时进行,必须为每个操作单独指定一个OVERLAPPED结构体。
此外,该示例还使用了CreateIoCompletionPort和GetQueuedCompletionStatus函数实现了IOCP机制,可以实现高效的异步操作。在接收线程中,将socket关联到IOCP上后,使用GetQueuedCompletionStatus函数从IOCP的队列中获取已完成的操作。在主线程中,可以使用PostQueuedCompletionStatus函数将自定义的操作提交到IOCP的队列中等待完成。
原文地址: http://www.cveoy.top/t/topic/bD67 著作权归作者所有。请勿转载和采集!