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

使用C Sockets实现客户端/服务端遇errno=101(网络不可达)问题求助

客户端连接服务端失败:errno=101(Network is unreachable)排查方案

我正在用C Socket实现简单的客户端/服务端程序,但客户端无法连接到服务端,报错errno=101: Network is unreachable。我已通过SSH接入私有网络,客户端和服务端在同一局域网,使用192.168.x.x段IP,按道理应该没问题,求解决思路。

相关代码

int main(int argc, char* argv[]) {

if (argc == 1)
{
int sockfd, connfd;
struct sockaddr_in servaddress, cliaddress;
socklen_t servaddr_size;
int n;

printf("Welcome to Chat!\n");

//create socket
sockfd = socket(AF_INET, SOCK_STREAM, 0); // IPv4, TCP, IP

if (sockfd == -1) 
{
  printf("Socket creation failed...\n");
  exit(0);
}
else 
{
  memset(&servaddress, '\0', sizeof(servaddress));

  servaddress.sin_family = AF_INET;
  servaddress.sin_port = htonl(0);
  servaddress.sin_addr.s_addr = htonl(INADDR_ANY);

  n = bind(sockfd, (struct sockaddr*)&servaddress, sizeof(servaddress));

  if (n < 0) 
  {
    printf("Socket bind failed...\n");
    exit(0);
  }
  
  socklen_t servsize = sizeof(servaddress);
  getsockname(sockfd, (struct sockaddr*) &servaddress, &servsize);

  printf("Waiting for a connection on %s ", inet_ntoa(servaddress.sin_addr));
  printf("port %d\n", ntohs(servaddress.sin_port));
  
  if ((listen(sockfd, 5)) != 0) 
  {
    printf("Listen failed...\n");
    exit(0);
  }
  else
  {
    printf("Server listening..\n");
  }

  while(1) {
    servaddr_size = sizeof(cliaddress);
    connfd = accept(sockfd, (struct sockaddr*)&cliaddress, &servaddr_size);

    if(connfd < 0) 
    {
      printf("can't accept connection...\n");
      exit(0);
    }
    else 
    {
      printf("Found a friend! You receive first.\n");
      
      servcomm(connfd);
      
      close(sockfd);
    }
  }
}
}

else if(argc == 2) 
{
printf("Invalid number of arguments.\n");
exit(1);
}

else if(argc > 2) 
{
int sockfd;
struct sockaddr_in servaddress;
char* portval;
char* ipval;

for(int i = 0; i < argc; i++) 
{
  if(strcmp(argv[i], "-s") == 0) 
  {
    ipval = argv[i+1];
    while(*ipval) {
      if((isdigit(*ipval) == 0) && (*ipval != '.')) 
      {
        printf("IP is not valid.\n");
        exit(0);
      }
      ipval++;
    }
  }
  if(strcmp(argv[i], "-p") == 0) 
  {
    portval = argv[i+1];
    while(*portval) {
      if(isdigit(*portval++) == 0) 
      {
        printf("Port is not valid.\n");
        exit(0);
      }
    }
  }
}

sockfd = socket(AF_INET, SOCK_STREAM, 0); 

if (sockfd == -1) 
{
  printf("Socket creation failed...\n");
  exit(0);
}

memset(&servaddress, '\0', sizeof(servaddress));

servaddress.sin_family = AF_INET;
servaddress.sin_port = htonl(atoi(portval)); 
servaddress.sin_addr.s_addr = inet_addr(ipval);

// printf("portval %s\n", portval);
// printf("ipval %s\n", ipval);
// printf("atoi %d\n", atoi(portval));
// printf("port %d\n", servaddress.sin_port);
// printf("ip %d\n", servaddress.sin_addr.s_addr);

printf("Connecting to server...\n");
errno = 0;

if(connect(sockfd, (struct sockaddr*)&servaddress, sizeof(servaddress)) != 0) {
  printf("connection to server failed...\n");
  printf("Error occurred while connecting, errno=%d, %s\n", errno, strerror(errno));
  exit(0);
}
else
{
  printf("Connected!\n");
  printf("Connected to a friend! You send first.\n");
}

clicomm(sockfd);

close(sockfd);
}

return 0;
}

排查与修复思路

1. 端口转换函数错误

客户端代码中设置端口用了htonl(atoi(portval)),但servaddress.sin_port是16位字段,正确的转换函数应该是htons()(转换16位整数),htonl()是转换32位整数,会导致端口值被错误扩展,服务器监听的端口和客户端连接的端口不匹配。

2. IP地址指针被篡改

客户端解析-s参数时,直接对ipval做自增遍历检查,导致最后ipval指向的是字符串末尾的空字符,后续调用inet_addr(ipval)传入的是空字符串,会返回INADDR_NONE(对应255.255.255.255广播地址),无法连接到正确服务器IP。

修复方法:保存原始IP指针,遍历用临时变量:

if(strcmp(argv[i], "-s") == 0) 
{
  char* original_ip = argv[i+1];
  char* temp_ip = original_ip;
  while(*temp_ip) {
    if((isdigit(*temp_ip) == 0) && (*temp_ip != '.')) 
    {
      printf("IP is not valid.\n");
      exit(0);
    }
    temp_ip++;
  }
  ipval = original_ip;
}

3. 服务器套接字错误关闭

服务器端accept成功后调用了close(sockfd);,这会关闭监听套接字,导致后续无法接受新连接。正确做法是关闭connfd(连接套接字),保留sockfd继续监听:

servcomm(connfd);
close(connfd);
// close(sockfd); 移除这行

4. 网络层面验证

  • 在服务器机器上执行ss -tulpn | grep <进程名>,确认服务端确实在监听预期的端口(INADDR_ANY表示监听所有网卡)。
  • 在客户端机器上用ping <服务器IP>测试网络连通性,确保没有路由问题。
  • 用telnet <服务器IP> <端口>手动尝试连接,排除防火墙、SELinux等系统级限制。
  • 检查SSH隧道的端口转发配置(如果有),确保没有端口冲突或转发错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 16:49:57