You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

未先发送消息时读取UDP数据报失败,错误码10022怎么解决?

问题分析与解决方案

错误码10022对应WSAEINVAL(无效参数),结合你的代码,问题出在两个核心方面:客户端缺少必要的错误检查,以及服务器的发送目标完全错误。

核心问题解析

  1. 服务器发送目标错误:你的服务器绑定了127.0.0.1:2368,但sendto调用时把数据发送到这个绑定的地址——相当于服务器在给自己发数据,根本不会传递到客户端。UDP是无连接协议,服务器必须明确知道客户端的地址才能发送数据。
  2. 客户端错误检查缺失:代码没有验证WSAStartup、socket调用是否成功,一旦这些步骤失败,后续recvfrom调用就会因无效socket或参数抛出10022错误。

修复后的代码

修复后的客户端代码

客户端先向服务器发送一个初始化消息,让服务器获取自身地址,之后等待接收服务器的消息:

// client
#include <iostream>
#include <string>
#include <thread>
#include <winsock2.h>

#pragma comment(lib, "ws2_32.lib")

int main(int argc, char* argv[])
{
    const std::string host = "127.0.0.1";
    const int port = 2368;
    WSADATA wsaData;
    
    // 检查WSAStartup初始化是否成功
    int wsa_ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (wsa_ret != 0) {
        std::cout << "WSAStartup初始化失败: " << wsa_ret << std::endl;
        return wsa_ret;
    }

    SOCKET client_socket = ::socket(AF_INET, SOCK_DGRAM, 0);
    // 检查socket创建是否成功
    if (client_socket == INVALID_SOCKET) {
        int err = WSAGetLastError();
        std::cout << "socket创建失败: " << err << std::endl;
        WSACleanup();
        return err;
    }

    sockaddr_in server_addr{};
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = inet_addr(host.c_str());
    int server_struct_length = sizeof(server_addr);

    // 发送初始化消息,让服务器获取客户端地址
    char init_msg[] = "init";
    int send_ret = ::sendto(client_socket, init_msg, sizeof(init_msg), 0, 
                           (struct sockaddr*)&server_addr, server_struct_length);
    if (send_ret == SOCKET_ERROR) {
        int err = WSAGetLastError();
        std::cout << "sendto发送失败: " << err << std::endl;
        closesocket(client_socket);
        WSACleanup();
        return err;
    }

    char readBuffer[100*1000];
    sockaddr_in sender_addr{};
    int sender_len = sizeof(sender_addr);
    // 接收服务器消息,sender_addr用于获取发送方地址
    int ret = ::recvfrom(client_socket, readBuffer, sizeof(readBuffer), 0, 
                        (struct sockaddr*)&sender_addr, &sender_len);
    if (ret == SOCKET_ERROR) {
        int err = WSAGetLastError();
        std::cout << "recvfrom接收失败: " << err << std::endl;
        closesocket(client_socket);
        WSACleanup();
        return err;
    }

    std::cout << "从服务器接收了 " << ret << " 字节数据" << std::endl;

    // 释放资源
    closesocket(client_socket);
    WSACleanup();
    return 0;
}

修复后的服务器代码

服务器先通过recvfrom获取客户端地址,之后循环向该地址发送消息:

// server
#include <iostream>
#include <string>
#include <thread>
#include <winsock2.h>

#pragma comment(lib, "ws2_32.lib")

int main(int argc, char* argv[])
{
    const std::string host = "127.0.0.1";
    const int port = 2368;
    WSADATA wsaData;
    
    int wsa_ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (wsa_ret != 0) {
        std::cout << "WSAStartup初始化失败: " << wsa_ret << std::endl;
        return wsa_ret;
    }

    SOCKET server_socket = ::socket(AF_INET, SOCK_DGRAM, 0);
    if (server_socket == INVALID_SOCKET) {
        int err = WSAGetLastError();
        std::cout << "socket创建失败: " << err << std::endl;
        WSACleanup();
        return err;
    }

    sockaddr_in server_addr{};
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = inet_addr(host.c_str());
    int server_struct_length = sizeof(server_addr);

    int bind_ret = ::bind(server_socket, (struct sockaddr*)&server_addr, server_struct_length);
    if (bind_ret == SOCKET_ERROR) {
        int err = WSAGetLastError();
        std::cout << "bind绑定失败: " << err << std::endl;
        closesocket(server_socket);
        WSACleanup();
        return err;
    }

    // 接收客户端的初始化消息,获取客户端地址
    char init_buf[100];
    sockaddr_in client_addr{};
    int client_addr_len = sizeof(client_addr);
    int recv_ret = ::recvfrom(server_socket, init_buf, sizeof(init_buf), 0,
                             (struct sockaddr*)&client_addr, &client_addr_len);
    if (recv_ret == SOCKET_ERROR) {
        int err = WSAGetLastError();
        std::cout << "recvfrom接收失败: " << err << std::endl;
        closesocket(server_socket);
        WSACleanup();
        return err;
    }

    char buffer[2050];
    // 循环向客户端地址发送消息
    for (;;) {
        int send_ret = ::sendto(server_socket, buffer, sizeof(buffer), 0,
                               (struct sockaddr*)&client_addr, client_addr_len);
        if (send_ret == SOCKET_ERROR) {
            int err = WSAGetLastError();
            std::cout << "sendto发送失败: " << err << std::endl;
            closesocket(server_socket);
            WSACleanup();
            return err;
        }
        std::cout << "向客户端发送了 " << send_ret << " 字节数据.\n";
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    // 释放资源(循环退出时执行)
    closesocket(server_socket);
    WSACleanup();
    return 0;
}

关键修复点

  • 服务器端:添加recvfrom获取客户端地址,后续sendto目标改为该客户端地址,而非服务器自身的绑定地址。
  • 客户端:补充WSAStartup、socket创建的错误检查;增加初始化消息让服务器知晓自身地址;recvfrom使用独立的sender_addr接收发送方信息,避免参数混淆。
  • 两端都完善了资源释放逻辑,确保closesocket和WSACleanup被正确调用。

内容的提问来源于stack exchange,提问作者Andy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 06:22:02