2013-09-01 2 views
1

Примечание: Это проект домашней работы, я попытаюсь записать оставшийся код, но не могу понять, почему это невозможно для подключения к входному URL.Невозможно подключиться к хосту с помощью getaddrinfo()

Мне был предоставлен скелетный код, который я немного изменил, чтобы получить входной URL. Ожидаемое использование может быть: ./a.out http://google.com

По какой-либо причине ему никогда не удается подключиться. Сообщение об ошибке «не удалось подключиться» всегда печатается. Позже мне нужно будет взять файл из URL-адреса и сохранить его в локальном каталоге, но я попытаюсь выяснить, как это сделать (я предполагаю, что он имеет отношение к recv() в коде ниже). В случае «http://google.com» я ожидал, что возьму «index.html».

Скелетный код использует connect(), но справочная страница для getaddrinfo() использует bind(), который, кажется, намного быстрее, но также не работает. Использование connect() он никогда не кажется, чтобы оставить для цикла (Edit: Он никогда не оставляет, потому что, кажется, застрял пытается подключиться):

#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; 
} 

Edit: Я заменил "8080" с "80" как рекомендовано Uku Loskit.

+1

Прекрасно работает для меня при подключении к местной службе. Когда какой-либо из ваших системных вызовов возвращает ошибку, вы должны получить доступ к 'errno' и распечатать сообщение об ошибке, иначе вы никогда не узнаете, где это происходит. –

+0

Почему вы ожидаете найти порт 8080? Значение по умолчанию для HTTP - 80. – tripleee

+0

Не знаю, я новичок в этом.Я попытался найти разницу между 8080 и 80 в Интернете, но не понял. Это было '' :: 1' и '' 8080 "' изначально – asimes

ответ

2

Ваша программа выглядит нормально для меня, запустить netcat на порту 8080 и Connet к хозяину:

$ 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 
$ 
+0

Ввод текста: 'echo" Hello "| ncat -l 8080', кажется, никогда не заканчивается. – asimes

+0

@asimes Сначала запустите 'netcat', а затем подключитесь. –

+0

В нем говорится: «Это nc из пакета netcat-openbsd. Альтернативный nc доступен в традиционном пакете netcat. использование: nc [-46DdhklnrStUuvzC] [-i interval] [-P proxy_username] [-p source_port ] \t [-s source_ip_address] [-T ToS] [-w timeout] [-X proxy_protocol] \t [-x proxy_address [: port]] [hostname] [port [s]] " – asimes

1

Вы должны подключаться к порту 80, а не 8080. Порт 80 по умолчанию используется для HTTP.

+0

Я сделал это изменение, спасибо. К сожалению, он до сих пор не подключен – asimes

+0

Как сказал Пол Гриффитс, он подключился, проблема теперь в 'recv()'. Еще раз спасибо – asimes

1

При изменении номера порта 80 и подключиться к http://google.com, он будет работать, как ожидалось, но виснет на вызов recv(), потому что HTTP-сервер ничего не отправит вам, пока вы его не попросите. Ответ Sp. Дает вам пример того, как это сделать, добавив вызов send() перед вызовом recv().

Что происходит прямо сейчас, вы подключаетесь к нему, и он ждет вас, чтобы рассказать ему, что вы хотите. То, что вы делаете, просто ждет, когда он отправит вам что-то с вашим звонком recv(), поэтому вы оба будете ждать, пока он не истечет.

+0

Все еще понимая, что означает его ответ, ха-ха. Еще раз спасибо – asimes

+0

Вам просто нужно добавить свой вызов 'send()'. Вам нужно отправить запрос на сервер, прежде чем он вам что-нибудь даст. Что происходит прямо сейчас, вы подключаетесь к нему, и он ждет, когда вы скажете это, что хотите. Что вы делаете, просто ждет, когда он отправит вам что-то с вашим вызовом 'recv()', поэтому вы оба будете ждать, пока он не истечет. –

Смежные вопросы