使用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()调用,同时调整相关逻辑。比如:
- 首先去掉
listen()调用(UDP不需要监听连接) - 当
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
相关产品推荐
相关产品推荐

