以下是一个简单的使用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的队列中等待完成。

请给我一个使用C++的IOCP UDP 发送和接收 例子需要多线程简单点

原文地址: http://www.cveoy.top/t/topic/bD67 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录