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

C语言TCP Socket跨设备连接失败问题求助

跨PC连接Socket客户端/服务器失败的排查与解决

问题描述

我用C语言开发了Socket客户端/服务器程序:服务器负责监听连接并打印客户端用户名,客户端需传入用户名、服务器IP和端口三个参数,连接服务器后发送用户名。程序在同一台电脑上运行正常,但跨PC连接时总是超时,提示Error connecting to host.。

补充测试场景:

  • 服务器(台式机)通过手机USB共享网络,客户端(笔记本)使用WiFi,无法连接
  • 改为服务器连有线网络、客户端连WiFi,两台设备均联网,但仍连接超时
  • 两台设备都通过有线连接同一路由器后,连接成功,推测需要联系学校IT部门

原始代码

client.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define PORT 4000
#define WORD_SIZE 256

int main(int argc, char * argv[]) {
    pthread_t tid;
    int sockfd;
    struct sockaddr_in serv_addr;
    struct hostent * server;

    if (argc != 4) 
    {
        printf("Not enough arguments, please inform:\n");
        printf("<username> <server_ip_adress> <port>");
        return -1;
    }

    char username[WORD_SIZE], server_ip[WORD_SIZE], port[WORD_SIZE];
    strcpy(username, argv[1]);
    strcpy(server_ip, argv[2]);
    strcpy(port, argv[3]);


    server = gethostbyname(server_ip);
    if (server == NULL) 
    {
        printf("Error: no such host\n");
        return -1;
    }

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
    {
        printf("Error opening socket\n");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    serv_addr.sin_addr = * ((struct in_addr * ) server->h_addr);
    bzero( & (serv_addr.sin_zero), 8);

    int status = connect(sockfd, (struct sockaddr * ) & serv_addr, sizeof(serv_addr));
    if (status < 0) 
    {
        printf("Error connecting to host.\n");
        return -1;
    }

    if (send(sockfd, username, WORD_SIZE, 0) < 0)
    {
        printf("Error sending username.\n");
        close(sockfd);
        return -1;
    }

    printf("Username sent.\n");
    close(sockfd);

    return 0;
}

server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 4000
#define WORD_SIZE 256

int main(int argc, char *argv[])
{
    int serverSockfd;
    socklen_t clilen;
    struct sockaddr_in serv_addr, cli_addr;

    if ((serverSockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        printf("Error creating the socket.\n");

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    serv_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(serverSockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
        printf("Error binding the socket.\n");
        return -1;
    }

    if (listen(serverSockfd, 5) < 0)
    {
        printf("Error on listening.\n");
        return -1;
    }

    int newSockfd;
    while (1) 
    {
        newSockfd = accept(serverSockfd, (struct sockaddr *)&cli_addr, &clilen);
        if (newSockfd < 0)
        {
            printf("Error on accept a new client.\n");
            continue;
        }

        char username[WORD_SIZE];
        if (recv(newSockfd, username, WORD_SIZE, 0) < 0)
        {
            printf("Error receiving username.\n");
            close(newSockfd);
            continue;
        }

        printf("User %s logged in.\n", username);
        close(newSockfd);
    }
}

问题分析与修复

一、代码层面的错误

  1. 客户端端口硬编码,忽略传入参数
    客户端代码中定义了#define PORT 4000,并直接使用该值设置端口,但程序要求用户传入端口参数,这会导致如果用户传入的端口不是4000,客户端仍会连接4000端口,直接引发连接失败。
    修复:将端口设置改为使用传入的参数:
// 替换原有的 serv_addr.sin_port = htons(PORT);
serv_addr.sin_port = htons(atoi(port));

同时建议添加端口参数的有效性校验,避免非数字输入导致的错误。

  1. 服务器socket创建失败未退出
    服务器创建socket失败后仅打印错误,未终止程序,后续的bind、listen操作会使用无效的文件描述符,引发隐性错误。
    修复:socket创建失败后直接退出:
if ((serverSockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
    printf("Error creating the socket.\n");
    return -1;
}
  1. accept调用前未初始化clilen
    服务器中clilen未初始化就传入accept函数,会导致未定义行为,可能影响连接建立。
    修复:在accept前初始化clilen:
while (1) 
{
    clilen = sizeof(cli_addr); // 添加这一行
    newSockfd = accept(serverSockfd, (struct sockaddr *)&cli_addr, &clilen);
    // ... 后续代码
}

二、网络环境层面的问题

从测试结果来看,核心问题是不同网络环境下的路由或防火墙限制:

  • 手机USB共享网络与WiFi属于不同网段,无路由规则允许通信,且手机可能拦截外部连接
  • 学校网络中,有线和WiFi可能属于不同VLAN(虚拟局域网),VLAN之间默认隔离,禁止跨VLAN内部连接
  • 服务器设备的防火墙可能拦截了4000端口的入站连接,即使同一局域网也需要手动开放

解决方案

  1. 先修复代码中的所有硬编码和错误处理问题,确保程序逻辑正确
  2. 网络排查步骤:
    • 用ping命令测试客户端与服务器的连通性:客户端执行ping 服务器IP,能正常通再尝试Socket连接
    • 临时关闭服务器设备的防火墙,或在防火墙上添加规则,允许4000端口的TCP入站连接
    • 若使用学校网络,联系IT部门确认是否允许跨VLAN连接,或申请开放4000端口的权限

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 04:39:34