C语言TCP套接字连接被拒绝(errno=111)问题排查求助
TCP客户端连接服务端出现errno=111(连接被拒绝)问题排查
我使用两台虚拟机模拟客户端-服务器架构,编写了C语言TCP客户端与服务端代码,但运行时出现errno=111(连接被拒绝)错误。不过使用nc命令测试时,两台机器可正常通信,希望找到问题原因及解决方法。
客户端代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <errno.h> int main(int argc, char ** argv) { //检查命令行是否传入端口 if (argc != 2) { printf("Usage: %s <port>", argv[0]); exit(0); } //控制变量、套接字和地址相关变量 int port = atoi(argv[1]); int sock; struct sockaddr_in addr; socklen_t addr_size; char buffer[1024]; int n; //创建套接字并检查结果 sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("[-] Error while creating socket.\n"); exit(1); } printf("[+] TCP socket created. \n"); memset(&addr, '\0', sizeof(addr));//初始化地址结构体为0 //设置地址属性 addr.sin_family = PF_INET; addr.sin_port = port; addr.sin_addr.s_addr = INADDR_ANY; //连接套接字 n = connect(sock, (struct sockaddr*)&addr, sizeof(addr)); if (n < 0) { printf("Error while connecting the socket...: %s\n", strerror(errno)); printf("Errno value = %d", errno); exit(1); } printf("[+] Client connected.\n"); bzero(buffer, 1024);//清空缓冲区 strcpy(buffer, "Hello World"); printf("Client: %s\n", buffer); send(sock, buffer, strlen(buffer), 0); //发送缓冲区中的消息 bzero(buffer, 1024); recv(sock, buffer, sizeof(buffer), 0); //接收服务器的响应 printf("Server: %s\n", buffer); close(sock); //关闭客户端连接 printf("[+] Disconnected from the server"); return 0; }
服务端代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> int main(int argc, char** argv) { //检查命令行是否传入端口 if (argc != 2) { printf("Usage: %s <port>", argv[0]); exit(0); } //定义所需变量 int port = atoi(argv[1]); //从命令行获取端口 int server_sock, client_sock; //服务器和客户端套接字 struct sockaddr_in server_addr, client_addr; //服务器和客户端地址结构体(IPv4) socklen_t addr_size; //地址结构体长度 char buffer[1024]; //消息传输缓冲区 int n; //控制变量 //创建服务器套接字 server_sock = socket(AF_INET, SOCK_STREAM, 0); //检查套接字创建是否成功 if (server_sock < 0) { perror("[-] Error while creating socket.\n"); exit(1); } printf("[+] TCP socket created. \n"); //初始化服务器地址结构体为0 memset(&server_addr, '\0', sizeof(server_addr)); //设置服务器地址属性 server_addr.sin_family = AF_INET; server_addr.sin_port = port; server_addr.sin_addr.s_addr = INADDR_ANY; //绑定套接字到指定端口 n = bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); //检查绑定是否成功 if (n < 0) { perror("[-] Error while binding the socket.\n"); exit(1); } printf("[+] Socket binded to the port %d\n", port); //设置服务器监听状态 int listenVar = 0; listenVar = listen(server_sock, 5); if (listenVar < 0) { perror("[-] Error while setup listening phase...\n"); exit(1); } printf("[+] Listening...\n"); //循环处理客户端连接 while(1) { addr_size = sizeof(client_addr); //客户端地址结构体长度 //接受客户端连接 client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &addr_size); if (client_sock < 0) { perror("[-]Error while accepting the connection"); exit(1); } char ipString[40]; //存储客户端IP的字符串 inet_ntop(AF_INET, &client_addr.sin_addr, ipString, sizeof(ipString)); //将IP转换为字符串格式 printf("[+] Client connected.\n Client IP:%s\n", ipString); //打印连接的客户端IP bzero(buffer, 1024); //清空缓冲区 recv(client_sock, buffer, sizeof(buffer), 0); //接收客户端消息 printf("Client: %s\n", buffer); //打印客户端消息 bzero(buffer,1024); //再次清空缓冲区 strcpy(buffer, "Hi from the server"); //写入服务器响应消息 printf("Server: %s\n", buffer); send(client_sock, buffer, strlen(buffer), 0); //发送响应消息给客户端 close(client_sock); //关闭客户端连接 printf("[+] Client disconnected.\n"); } return 0; }
问题原因及解决方法
核心问题点
- 客户端目标地址错误:客户端代码中
addr.sin_addr.s_addr = INADDR_ANY;是错误用法——INADDR_ANY是服务端用来绑定所有网卡地址的参数,客户端连接时必须指定服务端虚拟机的真实IP地址,否则客户端会尝试连接自身虚拟机的对应端口,自然被拒绝。 - 端口未转换为网络字节序:客户端和服务端代码中,
sin_port直接赋值为port,没有使用htons()函数将主机字节序转换为网络字节序,这会导致端口解析错误,服务端绑定的端口和客户端尝试连接的端口实际不匹配。 - 客户端参数缺失:当前客户端仅要求传入端口,没有传入服务端IP的参数,无法指定正确的连接目标。
具体修复步骤
客户端代码修改
- 调整命令行参数要求:将
argc != 2改为argc != 3,用法提示改为Usage: %s <server_ip> <port>,支持传入服务端IP和端口。 - 设置正确的服务端IP:用
inet_addr(argv[1])将命令行传入的IP字符串转换为网络字节序,赋值给addr.sin_addr.s_addr。 - 端口转换为网络字节序:用
htons(port)替换直接赋值的port。
修改后的客户端核心代码片段:
if (argc != 3) { printf("Usage: %s <server_ip> <port>", argv[0]); exit(0); } int port = atoi(argv[2]); // ... addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(argv[1]);
服务端代码修改
将绑定端口的代码改为网络字节序:
server_addr.sin_port = htons(port);
运行注意事项
- 先启动服务端,确认输出
[+] Listening...后再启动客户端。 - 客户端启动时传入服务端虚拟机的真实IP和端口,例如:
./client 192.168.1.100 8080。 - 确保两台虚拟机的防火墙已开放对应端口(如8080),避免被防火墙拦截连接。
内容的提问来源于stack exchange,提问作者NinoQuindici_Git
相关产品推荐
相关产品推荐

