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

Winsock UDP通信中添加bind代码后sendto调用失败(错误码10038)求助

问题分析与解决方案

首先,错误码10038对应的是WSAENOTSOCK,意思是你试图在一个非有效套接字句柄上执行socket操作。结合你的代码和现象,问题出在两个核心点上:

1. 错误的Bind目标

你现在把socket绑定到了远程设备的IP地址(172.10.1.2)和端口1600,这完全违背了bind函数的设计初衷:

  • bind的作用是将UDP套接字关联到本机的IP地址和端口,用来指定这个socket从哪个本地端口发送/接收数据;
  • 远程目标的地址应该只在sendto时指定,而不是绑定。

当你尝试绑定到一个不属于本机的IP地址时,即使bind返回成功,这个socket实际上已经处于异常状态,后续调用sendto自然会报错。

2. 不完整的错误处理

你的代码中,当bind失败时,虽然调用了closesocket(my_socket),但没有终止程序,后续代码依然会使用这个已经被关闭的无效套接字,这也会触发10038错误。


修正后的代码

下面是调整后的完整代码,我标注了关键修改点:

#ifndef UNICODE
#define UNICODE
#endif
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")

int main() {
    int iResult;
    WSADATA wsaData;
    SOCKET my_socket = INVALID_SOCKET;
    // 新增:用于绑定的本地地址结构体
    struct sockaddr_in local_addr;
    // 用于指定远程目标的地址结构体
    struct sockaddr_in remote_addr;
    unsigned short LocalPort = 0; // 0表示让系统自动分配本地端口
    unsigned short RemotePort = 1600;
    char SendBuf[1024] = "Look Here";
    int BufLen = (int)strlen(SendBuf) + 1; // 优化:只发送实际长度的内容,不用全发1024字节

    // 初始化两个地址结构体
    memset(&local_addr, 0, sizeof(local_addr));
    memset(&remote_addr, 0, sizeof(remote_addr));

    //----------------------
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR) {
        wprintf(L"WSAStartup failed with error: %d\n", iResult);
        return 1;
    }

    //---------------------------------------------
    // Create a UDP socket
    my_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (my_socket == INVALID_SOCKET) {
        wprintf(L"socket failed with error: %ld\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    //---------------------------------------------
    // 配置本地绑定地址:绑定到本机所有网卡(INADDR_ANY),端口由系统自动分配
    local_addr.sin_family = AF_INET;
    local_addr.sin_port = htons(LocalPort);
    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    // 绑定到本地地址
    iResult = bind(my_socket, (SOCKADDR*)&local_addr, sizeof(local_addr));
    if (iResult == SOCKET_ERROR) {
        wprintf(L"bind failed with error %u\n", WSAGetLastError());
        closesocket(my_socket);
        WSACleanup(); // 这里要加上Winsock清理
        return 1; // 绑定失败直接退出,避免后续使用无效socket
    }
    wprintf(L"bind returned success\n");

    //---------------------------------------------
    // 配置远程目标地址
    remote_addr.sin_family = AF_INET;
    remote_addr.sin_port = htons(RemotePort);
    inet_pton(AF_INET, "172.10.1.2", &remote_addr.sin_addr);

    //---------------------------------------------
    // 发送数据到远程设备
    wprintf(L"Sending a datagram to the receiver...\n");
    iResult = sendto(my_socket, SendBuf, BufLen, 0, (SOCKADDR*)&remote_addr, sizeof(remote_addr));
    if (iResult == SOCKET_ERROR) {
        wprintf(L"sendto failed with error: %d\n", WSAGetLastError());
        closesocket(my_socket);
        WSACleanup();
        return 1;
    }
    wprintf(L"Sent %d bytes successfully\n", iResult);

    //---------------------------------------------
    // 关闭套接字
    wprintf(L"Finished sending. Closing socket.\n");
    iResult = closesocket(my_socket);
    if (iResult == SOCKET_ERROR) {
        wprintf(L"closesocket failed with error: %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    //---------------------------------------------
    // 清理退出
    wprintf(L"Exiting.\n");
    WSACleanup();
    return 0;
}

关键修改说明

  • 分离了本地绑定地址和远程目标地址两个结构体,彻底避免地址混淆;
  • bind时使用INADDR_ANY,表示让socket监听本机所有可用网卡的端口,端口设为0则由系统自动分配(如果你需要固定本地端口,把LocalPort改成你想要的数值即可);
  • 修复了bind失败后的错误处理:添加WSACleanup并直接返回,防止后续代码使用无效套接字;
  • 优化了发送缓冲区长度:只发送实际内容的长度,减少不必要的数据传输。

额外注意事项

  • 如果你不需要指定本地端口,其实UDP客户端完全可以不用调用bind——系统会在第一次调用sendto时自动为socket分配一个随机本地端口,这也是你之前移除bind后能正常发送的原因;
  • 确保你的笔记本和目标设备在同一个网络段,或者路由可达,否则即使代码正确,也可能出现无法发送的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 01:57:52