【问题标题】:Can connect to my program through localhost, but cannot connect using other computers on network可以通过 localhost 连接到我的程序,但无法使用网络上的其他计算机连接
【发布时间】:2019-05-22 00:30:48
【问题描述】:

我编写了一个程序来通过网络(或可能是互联网)播放滴答声。我是用 C 写的。

当我在同一台机器上运行主机和客户端时,程序运行良好。但是,当它在两台不同的机器上运行时,我无法建立连接。

我在两台计算机上都使用 Ubuntu 18.04 LTS。我不明白为什么这很重要,但是一个通过以太网连接到路由器。另一个以无线方式连接到网络。 ufw verbose 表明防火墙在两台计算机上都处于非活动状态。

我已经尝试过的事情:

  1. 将服务器名称添加到 /ect/hosts 中的主机,而不是键入 程序参数中的 IP 地址(在本地双向工作 机器,不能通过网络工作)。
  2. 向路由器防火墙添加防火墙例外。
  3. 端口转发我在路由器上使用的端口 (5001)。
  4. nmap 到运行主机的计算机的 ip 显示端口 5001/tcp 已通过服务“commplex-link”打开
  5. 可以通过网络从远程计算机远程登录到主机。

void network_host(void) {

    int sockfd, newsockfd, portno, clilen;
    struct sockaddr_in serv_addr, cli_addr;
    int n;
    struct game *main_game = createboard();

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if (sockfd < 0) {
        perror("On opening socket ERROR: \n");
        exit(1);
    }

    memset(&serv_addr, 0, sizeof serv_addr );
    portno = 5001;

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

    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof serv_addr ) < 0 ) {
        perror("On socket binding ERROR: \n");
        exit(1);
    }

    printf("Waiting for opponent . . .\n");
    listen(sockfd, 1);
    clilen = sizeof cli_addr;
    memset(&cli_addr, 0, clilen);

    newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); 

    if (newsockfd < 0) {
        perror("On accepting connection ERROR: \n");
        exit(1);
    }

    printf("Opponent connected!\n");

    while (main_game->play) {
            printboard(main_game);
            entermove(main_game, GAME_HOST, newsockfd);
            checkwin(main_game);
    }
}

void network_client(char *host_name) {

    int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    struct game *main_game = createboard();

    portno = 5001;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if (sockfd < 0) {
        perror("Error opening socket");
        exit(1);
    }

    server = gethostbyname(host_name);

    if (server == NULL) {
        fprintf(stderr, "Error, no such host.\n");
        exit(0);
    }

    memset((char *) &serv_addr, 0, sizeof serv_addr);
    serv_addr.sin_family = AF_INET;
    memcpy((char *)server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
    serv_addr.sin_port = htons(portno);

    if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("Error connecting.\n");
        exit(1);
    }

    while (main_game->play) {
        printboard(main_game);
        entermove(main_game, GAME_CLIENT, sockfd);
        checkwin(main_game);
    }
}

由于这个程序在连接到本地主机时可以工作,nmap 显示端口远程打开,我可以远程登录到程序,我完全不知道下一步该去哪里。

在我看来,它不是编码错误,因为它可以在本地工作,但由于我可以 telnet 进入程序,所以它似乎不应该是网络错误。

我愿意回溯这些步骤(也许其中一些我只做对了一半)。但也愿意接受其他可能的想法。

【问题讨论】:

  • 贴出的代码无法编译!您希望我们如何重现该问题?请发布minimal reproducible example,以便我们重现问题并帮助您调试。
  • 您在尝试通过网络访问另一台计算机时使用什么主机名?
  • OT:始终检查调用 C 库函数的返回值,例如:socket()accept()listen() 等,以确保操作成功

标签: c sockets


【解决方案1】:

这一行是你的问题所在

memcpy((char *)server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);

memcpy 被定义为获取目标、源和大小......所以你复制的东西是错误的,因为server 是地址所在的位置。交换东西,它应该工作得很好......

memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);

您不需要转换任何东西,因为首先memcpy 的这两个参数应该是void * 而不是char *,其次,指针会自动转换为void *

【讨论】:

  • 更好的解决方案是将gethostbyname() 替换为getaddrinfo() 并让它为您分配和填充适当的sockaddr 结构。
  • @Chris,非常感谢。很抱歉,我不得不找人纠正我的代码。这是一个真正的教训,即使某些东西看起来有效,也可能没有。下次我肯定会更加小心我的代码。另外,感谢有关类型转换的附加提示。我在那里有点“高兴”,我绝对可以看到这可能会隐藏一些错误并导致问题发生。我还是新手,主要是靠自己学习(像你这样的好心人除外)。
  • @Remy 感谢您的提示和链接。不过,在我使用它之前,我会阅读并学习该功能,但是获得这种输入非常棒,因为尝试自己掌握所有这些功能几乎是压倒性的。我什至不知道它的存在。然而,需要注意的一点是,我似乎使用了一种可能已经过时的做法。我是否应该假设 getaddrinfo()(以及扩展名 gethostbyname())应该返回地址列表。我刚刚注意到 netdb.h 说“#define h_addr h_addr_list[0] /* 为了向后兼容 */”
  • @NicholasR 是的,gethostbyname()getaddrinfo() 都返回地址列表。您应该尝试连接到每个地址,直到一个成功。一个主机名可以有多个 IP,您可能没有通往所有 IP 的网络路由,因此请全部尝试。 gethostbyname()getaddrinfo() 弃用,因为后者同时支持 IPv4 和 IPv6,可重入等
  • 非常感谢雷米的帮助。你帮了大忙。就像我说的,自己学习这些细微差别非常困难。我必须学会在查看文档方面做得更好,但我怀疑这是一项需要相当长的时间来培养的技能。
猜你喜欢
  • 2023-03-30
  • 1970-01-01
  • 2018-02-28
  • 2013-08-17
  • 2013-08-26
  • 2012-09-30
  • 2019-11-07
  • 2017-04-08
  • 2014-02-08
相关资源
最近更新 更多