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

使用select()处理UDP套接字时调用accept()报‘Operation not supported’错误

问题根源与解决方案

你碰到的这个错误其实很好理解——UDP是无连接协议,accept()是TCP专属的系统调用,UDP套接字完全不支持这个操作,所以调用它必然会返回"Operation not supported"错误。

为什么原代码没问题?

原代码用的是SOCK_STREAM(TCP套接字),TCP是面向连接的协议:服务器先listen()监听端口,客户端发起connect()请求后,服务器需要通过accept()来接受这个连接,得到一个专门用于和该客户端通信的新套接字。但UDP的工作模式完全不同,它不需要提前建立连接,客户端可以直接向服务器的UDP端口发送数据包,服务器只需要通过原有的UDP套接字接收数据即可。

怎么修改你的代码?

你需要把代码中调用accept()的部分,替换成UDP对应的recvfrom()调用,同时调整相关逻辑。比如:

  1. 首先去掉listen()调用(UDP不需要监听连接)
  2. 当select()检测到UDP套接字可读时,直接用recvfrom()接收数据,这个函数会同时返回发送方的地址信息

修改后的核心代码片段大概是这样:

// 初始化UDP套接字部分(你的这部分是对的)
if( (master_socket = socket(AF_INET , SOCK_DGRAM , 0)) == 0) {
    perror("socket failed");
    exit(EXIT_FAILURE);
}

// 绑定地址(这部分和TCP类似,没问题)
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( 8888 );
if (setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
    perror("setsockopt");
    exit(EXIT_FAILURE);
}
if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0) {
    perror("bind failed");
    exit(EXIT_FAILURE);
}

// 去掉listen()调用,UDP不需要这个!

// 进入select循环部分
fd_set readfds;
while(1) {
    FD_ZERO(&readfds);
    FD_SET(master_socket, &readfds);
    int max_sd = master_socket;

    // 调用select等待可读事件
    int activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);
    if ((activity < 0) && (errno!=EINTR)) {
        perror("select error");
    }

    // 如果UDP套接字可读
    if (FD_ISSET(master_socket, &readfds)) {
        struct sockaddr_in client_addr;
        socklen_t client_addr_len = sizeof(client_addr);
        char buffer[1024] = {0};
        ssize_t recv_len = recvfrom(master_socket, buffer, sizeof(buffer)-1, 0,
                                   (struct sockaddr*)&client_addr, &client_addr_len);
        if(recv_len < 0) {
            perror("recvfrom failed");
            continue;
        }
        // 处理收到的数据,比如打印出来
        printf("Received from %s:%d: %s\n", inet_ntoa(client_addr.sin_addr),
               ntohs(client_addr.sin_port), buffer);
    }
}

额外提醒

  • UDP不需要维护多个连接套接字,所有客户端的数据都通过同一个UDP套接字接收
  • select()监听UDP套接字的逻辑是成立的:当有数据包到达时,套接字会被标记为可读
  • 如果需要向客户端回复数据,可以用sendto(),把recvfrom()得到的客户端地址传进去就行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:41:22