2

我想连接到一个有点洪流的跟踪器,http ://tracker.thepiratebay.org 。gethostbyname() 一直返回 null,我应该如何解决这个问题?你还发现这段代码还有什么问题吗?

    int sock;
    struct sockaddr_in servAddr; 
    int portNum = 80;

    if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){
          printf("fail create socket");
          return 0;
    }

    char *path = "http://tracker.thepiratebay.org/";
    struct hostent *hp = gethostbyname(path);   
    if(hp==NULL){
        printf("null");
    else{

        memset(&servAddr, 0, sizeof(servAddr));   
        servAddr.sin_family = AF_INET;                 
        memcpy( (char *) &servAddr.sin_addr.s_addr, (char *)  hp->h_addr, hp->h_length );
        servAddr.sin_port   = htons(portNum);    
    }

    //send request to tracker server 
    if (send(sock, requestToSend, strlen(requestToSend), 0) != strlen(requestToSend)){
        printf("fail send");
        return 0;
    }
4

1 回答 1

7

这里的问题是这http://tracker.thepiratebay.org/是一个 URL,但gethostbyname()只需要主机名。主机名是tracker.thepiratebay.org

如果您只使用libcurl会更容易,它将为您处理所有 HTTP 内容。在连接到 HTTP 服务器的应用程序中使用 libcurl 是非常常见的;这是一个很棒的图书馆。它肯定比套接字编程更容易。

采用getaddrinfo()

现代的替代方案gethostbyname()getaddrinfo(). 这并不是gethostbyname()没有做你想做的事,而是getaddrinfo()在所有可以想象的方式上都做得更好。

struct addrinfo hint, *ap;
memset(&hint, 0, sizeof(hint));
hint.ai_family = AF_UNSPEC;
hint.ai_socktype = SOCK_STREAM;
int r = getaddrinfo("tracker.thepiratebay.org", "http", &hint, &ap);

这不仅会为您提供所需主机的地址,还会填写端口号。你可以"http"作为端口使用,也可以作为端口使用"80",它们是一样的(只要/etc/services有正确的入口)。

其他问题

这条线是错误的。

memcpy( (char *) &servAddr.sin_addr.s_addr, (char *)  hp->h_addr, hp->h_length );

你不知道它gethostbyname()返回了一个 IPv4 地址,尝试将它复制到一个struct sockaddr_in. 如果gethostbyname()返回一个 IPv6 地址,你刚刚破坏了你的堆栈,你的程序将会崩溃——或者更糟糕的是,它可能不会崩溃。

检查它是否返回 IPv4 地址,或者简单地复制hp->h_addrstruct sockaddrmalloc(hp->h_length). 这有点难看,但它就是这样。

最后,将论点转换为 是错误的memcpy()。这不是错误,但它是错误的。不要这样做,否则可能会导致合法的编译器错误被抑制,例如,如果您不小心将to 强制int转换为char *.

于 2012-12-04T04:01:24.440 回答