简易Socket程序在Ubuntu WSL中调用accept()失败,errno=22
跨平台Socket服务端accept()错误排查(错误码22)
问题描述
在Ubuntu WSL环境运行以下跨平台Socket服务端代码时,程序执行到accept()步骤失败,错误码为22。已排查端口8080未被占用、使用sudo运行程序、关闭防火墙及网络防护工具,但问题仍未解决。
服务端代码
#if defined (_WIN32) #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0600 #endif #include <winsock2.h> #include <ws2tcpip.h> #pragma comment (lib, "ws2_32.lib") #define ISVALIDSOCKET(s) ((s) != INVALID_SOCKET) #define CLOSESOCKET(s) closesocket(s) #define GETSOCKETERRNO() (WSAGetLastError()) #else #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <unistd.h> #include <arpa/inet.h> #include <errno.h> #include <stdio.h> #include <string.h> #include <time.h> #define ISVALIDSOCKET(s) ((s) >= 0) #define CLOSESOCKET(s) close(s) #define SOCKET int #define GETSOCKETERRNO() (errno) #endif int main(void) { printf("Configuring local address ...\n"); struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; struct addrinfo *bind_address; getaddrinfo(0, "8080", &hints, &bind_address); printf("Creating socket...\n"); SOCKET socket_listen; socket_listen = socket(bind_address->ai_family, bind_address->ai_socktype, bind_address->ai_protocol); if (!ISVALIDSOCKET(socket_listen)) { fprintf(stderr, "socket() failed. (%d)", GETSOCKETERRNO()); return 1; } printf("Binding socket to local address...\n"); if (bind(socket_listen, bind_address->ai_addr, bind_address->ai_addrlen)) { fprintf(stderr, "bind() failed. (%d)\n", GETSOCKETERRNO()); return 1; } freeaddrinfo(bind_address); printf("Waiting for connection...\n"); struct sockaddr_storage client_address; socklen_t client_len = sizeof(client_address); printf("running the accept function\n"); SOCKET socket_client = accept(socket_listen, (struct sockaddr*) &client_address, &client_len); if (!ISVALIDSOCKET(socket_client)) { fprintf(stderr, "accept() failed. (%d)\n",GETSOCKETERRNO()); return 1; } printf("Client is connected..."); char address_buffer[100]; getnameinfo((struct sockaddr*)&client_address, client_len, address_buffer, sizeof(address_buffer), 0, 0, NI_NUMERICHOST); printf("%s\n", address_buffer); printf("Reading request...\n"); char request [1024]; int bytes_recieved = recv(socket_client, request, 1024,0 ); printf("Recieved %d bytes .\n", bytes_recieved); printf("%.*s", bytes_recieved,request); printf("Sending response...\n"); const char *response = "HTTP/1.1 200 OK\r\n" "Connection: close:\r\n" "Content-Type: text/plain\r\n\r\n" "Local time is: "; int bytes_sent = send(socket_client, response, strlen(response), 0); printf("Send %d of %d bytes.\n", bytes_sent, (int)strlen(response)); time_t timer; time (&timer); char *time_msg = ctime(&timer); bytes_sent = (socket_client, time_msg, strlen(time_msg), 0); printf("Send %d of %d bytes.\n", bytes_sent, (int)strlen(time_msg)); printf("Closing connection...\n"); CLOSESOCKET(socket_client); printf("Closing listening socket...\n"); CLOSESOCKET(socket_listen); #if defined(_WIN32) WSACleanup(); #endif printf("Finished.\n"); return 0; }
错误现象
程序运行输出如下后终止:
Configuring local address ... Creating socket... Binding socket to local address... Waiting for connection... accept() failed. (22)
原因分析
错误码22对应Linux下的EINVAL,触发该错误的核心原因是:监听套接字未调用listen()函数就直接执行accept()。TCP套接字的正确流程是socket() -> bind() -> listen() -> accept(),缺少listen()会导致accept()参数无效,返回EINVAL。
另外代码中还有一处语法错误:发送时间字符串的语句缺少send关键字,会导致编译警告或运行时错误。
解决方法
在
bind()完成后、accept()之前添加listen()调用:printf("Listening on socket...\n"); if (listen(socket_listen, 10) < 0) { fprintf(stderr, "listen() failed. (%d)\n", GETSOCKETERRNO()); return 1; }第二个参数
10是监听队列的最大长度,可根据需求调整。修复发送时间字符串的语法错误,补全
send关键字:bytes_sent = send(socket_client, time_msg, strlen(time_msg), 0);
修改后的完整代码可正常在Ubuntu WSL环境运行,等待客户端连接并响应请求。
内容的提问来源于stack exchange,提问作者Fuhad
相关产品推荐
相关产品推荐

