【问题标题】:Unable to connect to host using getaddrinfo()无法使用 getaddrinfo() 连接到主机
【发布时间】:2013-09-01 20:39:24
【问题描述】:

注意:这是一个家庭作业项目,我会尝试编写剩下的代码,但无法弄清楚为什么无法连接到输入 URL。

我得到了一些骨架代码,我对其进行了一些修改以接收输入 URL。预期用法可能是:./a.out http://google.com

无论出于何种原因,它都无法成功连接。始终打印错误消息“无法连接”。稍后我需要从 URL 中获取一个文件并将其保存到本地目录,但我会尝试弄清楚如何做到这一点(我的猜测是它与下面代码中的 recv() 有关)。在“http://google.com”的情况下,我应该使用“index.html”。

骨架代码使用connect(),但getaddrinfo() 的手册页使用bind(),这似乎要快得多,但也不起作用。使用 connect() 它似乎永远不会离开 for 循环(编辑:它永远不会离开,因为它似乎在尝试连接时卡住了):

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char** argv) {
        // Alex: Input usage (expecting one URL)
        if (argc != 2) {
                printf("Usage: ./hw1 URL\n");
                exit(1);
        }

        // Alex: Set noHttp as argv[1] and remove "http://"
        char* noHttp = argv[1];
        char http[] = "http://";
        if (strlen(noHttp) > 7 && !strncmp(noHttp, http, 7)) noHttp += 7;
        else {
                printf("Invalid URL, expecting http://host/path\n");
                exit(1);
        }
        printf("%s\n", noHttp);

        struct addrinfo hints;
        struct addrinfo* result, * rp;
        int sock_fd, s;

        // Alex: I moved assigning hints.ai_socktype after memset()
        memset(&hints, 0, sizeof(struct addrinfo));
        //hints.ai_socktype = SOCK_STREAM;

        s = getaddrinfo(noHttp, "8080", &hints, &result); // To Stack Overflow: This changed to "80", I am leaving it here because there are comments about it
        if (0 != s) {
                perror("Error populating address structure");
                exit(1);
        }

        int i = 0;
        for (rp = result; rp != NULL; rp = rp->ai_next) {
                printf("i = %d\n", i);
                i++;

                //printf("rp->ai_flags = %d\n", rp->ai_flags);
                printf("rp->ai_family = %d\n", rp->ai_family);
                printf("rp->ai_socktype = %d\n", rp->ai_socktype);
                printf("rp->ai_protocol = %d\n", rp->ai_protocol);

                sock_fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
                printf("sock_fd = %d\n", sock_fd);
                if (sock_fd == -1) continue;

                // Success
                if (connect(sock_fd, rp->ai_addr, rp->ai_addrlen) != -1) break;
                close(sock_fd);
        }

        if (rp == NULL) {
                fprintf(stderr, "could not connect\n");
                exit(1);
        }

        freeaddrinfo(result);

        char buf[255];
        memset(&buf, 0, sizeof(buf));

        int recv_count = recv(sock_fd, buf, 255, 0);
        if (recv_count < 0) {
                perror("Receive failed");
                exit(1);
        }

        printf("%s",buf);
        shutdown(sock_fd, SHUT_RDWR);
        return 0;
}

编辑:我按照 Uku Loskit 的建议将 "8080" 替换为 "80"。

【问题讨论】:

  • 连接本地服务时对我来说很好。当您的任何系统调用返回错误时,您应该访问errno 并打印出错误消息,否则您将永远不知道哪里出错了。
  • 为什么会发现 8080 端口是开放的? HTTP 的默认值为 80。
  • 我不知道,我对此很陌生。我试图在网上查找8080和80之间的差异,但不明白。它最初有 "::1 和 "8080"
  • ::1 只是localhost 的 IPv6 简写。它所说的“最初”无关紧要,如果您不尝试连接到您不知道应该可用的服务,那么难怪它不起作用。
  • 谢谢,我改了,还是不行

标签: c getaddrinfo


【解决方案1】:

你的程序在我看来没问题,在端口 8080 上运行 netcat 并连接到主机:

$ echo "Hello" | ncat -l 8080

将返回:

$ gcc -Wall sample.c 
$ ./a.out http://127.0.0.1
127.0.0.1
i = 0
rp->ai_family = 2
rp->ai_socktype = 1
rp->ai_protocol = 6
sock_fd = 3
Hello
$ 

要连接HTTP,需要先发送HTTP请求,否则会阻塞,在第64行后添加:

    freeaddrinfo(result);

    send(sock_fd, "GET / HTTP/1.1\n\n", 16, 0); // HTTP request

    char buf[255];
    memset(&buf, 0, sizeof(buf));

这将发送请求:

GET / HTTP/1.1

并将端口更改为80,它应该可以工作:

$ ./a.out http://google.com
google.com
i = 0
rp->ai_family = 2
rp->ai_socktype = 1
rp->ai_protocol = 6
sock_fd = 3
HTTP/1.1 200 OK
Date: Sun, 01 Sep 2013 21:05:16 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
P3P: CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151
$ 

【讨论】:

  • 打字:echo "Hello" | ncat -l 8080 似乎永远写不完。
  • @asimes 先运行netcat,然后连接。
  • 它说,“这是来自 netcat-openbsd 包的 nc。netcat-traditional 包中提供了另一种 nc。用法:nc [-46DdhklnrStUuvzC] [-i interval] [-P proxy_username ] [-p source_port] [-s source_ip_address] [-T ToS] [-w timeout] [-X proxy_protocol] [-x proxy_address[:port]] [hostname] [port[s]]"
  • @aimes 我使用ncat 的ncat 版本nmap,你有经典版本nc。我猜命令应该是echo "Hello" | nc -l -p 8080。
  • 它只是给了我同样的信息 echo "Hello" | nc -l -p 8080。我真的不明白这应该做什么
【解决方案2】:

您应该连接端口 80,而不是 8080。端口 80 是 HTTP 的默认端口。

【讨论】:

  • 我确实做了这个改变,谢谢。不幸的是,它仍然无法连接
  • 正如 Paul Griffiths 指出的那样,它确实连接了,现在问题出在 recv() 上。再次感谢您
【解决方案3】:

当您将端口号更改为 80 并连接到 http://google.com 时,它会按预期工作,但会挂在 recv() 调用上,因为 HTTP 服务器在您询问之前不会向您发送任何内容为了某件事。 Sp. 的回答为您提供了一个示例,说明如何在您的 recv() 呼叫之前添加一个 send() 呼叫。

现在发生的事情是你正在连接到它,它正在等待你告诉它你想要什么。你正在做的只是等待它通过你的recv() 呼叫向你发送一些东西,所以你们都将等到它超时。

【讨论】:

  • 还在理解他的回答是什么意思,哈哈。再次感谢
  • 您只需要添加他的send() 呼叫。您需要向服务器发送请求,然后它才会给您任何信息。现在发生的事情是你正在连接到它,它正在等待你告诉它你想要什么。 你正在做的只是等待它通过你的recv()呼叫向你发送一些东西,所以你们都将等到它超时。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-29
  • 2013-07-31
  • 2016-04-03
  • 2014-05-01
  • 2015-12-30
相关资源
最近更新 更多