2010-09-17 6 views
1

Я пытаюсь написать клиент TCP, который делает следующие вещи:Как читать ответ сокета в c?

1. Establish TCP connection to webserver 
2. Accept GET request command from user's console 
3. Client should get a reply back from webserver after each GET request. 

У меня трудное время для 3-го состояния. Я не получил ответа от веб-сервера.

Вот мой код:

s = connectTCP(host, service); 
while (fgets(buf, sizeof(buf), stdin)) { 
    buf[LINELEN-2]='\r'; /* ensure catridge return */ 
    buf[LINELEN-1]='\n'; /* ensure line feed return */ 
    buf[LINELEN] = '\0'; /* ensure line null-terminated */ 
    outchars = strlen(buf); 
    (void) write(s, buf, outchars); 
    printf("Start reading from socket...\n"); 
    fflush(stdout); 
    while((n = read(s, buf, LINELEN)) > 0) { 
    buf[n] = '\0'; /* ensure null-terminated */ 
    (void) fputs(buf, stdout); 
    fflush(stdout); 
    } 
} 

ответ

1

Запрос HTTP завершается два возврата каретки-перевод строки ("\ г \ п \ г \ n "). То, как вы строите свой запрос, даже не гарантирует его наличия. Может быть, что-то вроде:

while (fgets(buf, sizeof(buf) - 3, stdin)) { 
    size_t outsz = strlen(buf); 
    if (outsz > 0 && buf[outsz - 1] == '\n') 
     outsz--; 
    strcpy(buf + outsz, "\r\n\r\n"); 
    write(s, buf, outsz + 4); 
+0

Это не наносит вреда, но на самом деле не требуется большинство серверов (и вы можете даже использовать один '\ n' вместо' \ r \ n'). – kriss

+0

@caf 'fgets()' только заполняет символы 'size - 1' данными и всегда добавляет нуль, поэтому' -3' в порядке. «Write» включает в себя длину отправляемых данных, поэтому строка не должна заканчиваться с NUL-завершением. Тем не менее, 'strcpy()' (или, может быть, 'strcat()'), вероятно, лучше. – llasram

+0

Согласившись с необходимостью nul-terminator для 'write()' - вместо этого использовать 'memcpy()'. – caf

0

Какие розетки вы используете? Если вы используете (Windows) Berkley сокетов вы можете использовать select для проверки данных и recv/recvfrom получить данные

+0

Я использую гнезда berkley в ubuntu. как использовать select? – root

+0

Мне очень нравится руководство Beej по созданию сетей: http://beej.us/guide/bgnet/ – raven

+0

Да, это отличный гид, особенно для пользователей Linux/Unix :) – Necrolis

0

В этом коде есть несколько открытых отверстий, которые могут привести к этой проблеме. На самом деле я сделал ставку на 2-й раз.

1- действительно соединениеTCP действительно работает? Действительно ли он вернул рабочий TCP-сокет. Вы можете легко закрыть ту, которая проверяет наличие ошибок при вызове write() вместо того, чтобы их лишить.

2 Если LINELEN является константой, такой как размер массива, то размещение \r\n в конце массива не поможет, если между вводом пользователя и концом массива существует мусор (вероятность того, является некоторым 0). sizeof(buf) - это максимальная юридическая ценность, не обязательно размер того, что пользователь наберет.

3- double \r\n не требуется, достаточно одного '\ n' (соглашения unix).

4 - использование интерактивного пользовательского ввода для тестирования, как правило, не очень хорошая идея, это делает код более сложным для отладки и тестирования.

5 - остерегайтесь писать в позиции n в вашем буфере, если буфер чтения заполнен, он может быть один за концом буфера.

5 - если вы хотите больше, чем просто отправить одну команду и получить ответ, вам придется написать более сложный код, который управляет как write(), так и read(). В качестве другого плаката предлагаемый выбор может быть хорошей идеей (вероятно, простой, чем поток). Вы также можете работать в блокировке более чередующихся команд, отправленных и полученных, но все это, вероятно, для других вопросов.

Ниже приведен фрагмент кода (протестирован на Linux с gcc), который дает ответ. Не так уж и отличается от вас первоначальный, надеюсь, что это поможет вам закрыть лазейки.

#include <sys/types.h> 
#include <sys/socket.h> 
#include <errno.h> 
#include <fcntl.h> 
#include <sys/un.h> 
#include <netdb.h> 
#include <arpa/inet.h> 
#include <unistd.h> 
#include <stdio.h> 
#include <stdlib.h> 

enum { 
    LINELEN = 1024 
}; 

int main(){ 
    char buf[LINELEN]; 
    int n = 0; 
    unsigned int option_len; 
    int allow_reuse = 1; 
    int sck = socket(PF_INET, SOCK_STREAM, 0); 
    char * ip = "www.google.com"; 
    char * command = "GET http://www.google.com\n"; 

    /* connect to socket */ 
    struct sockaddr_in s; 
    memset(&s, 0, sizeof(struct sockaddr_in)); 
    s.sin_family = AF_INET; 
    s.sin_port = htons(80); 
    s.sin_addr.s_addr = inet_addr(ip); 
    if (s.sin_addr.s_addr == INADDR_NONE) { 
     struct hostent *h = gethostbyname(ip); 
     if (!h) { 
      printf("DNS resolution failed for %s\n", ip); 
      exit(0); 
     } 
     s.sin_addr.s_addr = *((int*)(*(h->h_addr_list))); 
    } 
    connect(sck, (struct sockaddr*)&s, sizeof(s)); 

    /* write command */ 
    printf("Write to socket...\n"); 
    write(sck, command, strlen(command)); 

    /* get answer */ 
    printf("Start reading from socket...\n"); 
    while((n = read(sck, buf, LINELEN-1)) > 0) { 
     buf[n] = '\0'; /* ensure null-terminated */ 
     fputs(buf, stdout); 
    } 
} 
Смежные вопросы