read () не читает полный http ответ - PullRequest
1 голос
/ 25 марта 2012

Я начинаю использовать сокеты на языке программирования Си. Я пытаюсь сделать простой http-запрос и сохранить буфер, полученный из read () в моем буфере. Для этого я использую указатели / realloc(), программы на C работают нормально, не компилируют ошибок, но читают только часть ответа http.

Например, если я попытаюсь получить бинарный файл логотипа Google: http://www.google.com/images/srpr/logo3w.png Content-Length скажет 7007 байт, но strlen(buffer) скажет 5146 для меня. Я считаю, что ошибка здесь - моя buf_size и realloc() почему bytesreaded равно 7337, а 330 байт, как я полагаю, имеет заголовки.

Вот мой код:

char *
httpget(const char * domain, const int port, const char * headers)
{
    int sockfd; /* Socket file descrption */
    int buf_size = MAX_BUFFER_SIZE;

    struct sockaddr_in  sock_addr; 
    struct hostent  *   host;

    char * buffer;
    char * newbuf;
    char * tbuf;

    sockfd = socket(AF_INET, /* Uses IPV4 Internet protocols */
                    SOCK_STREAM, /* Uses the TCP (Transfer Communication Protocol) */
                    0  /* "0" for socket () function choose the correct protocol based on the socket type. */
                    );

    if( sockfd == -1 )
    {
        return NULL;
    }

    host = gethostbyname(domain);

    if( NULL == host )
    {
        close(sockfd);
        return NULL;
    }

    memset(&sock_addr, '\0', sizeof(sock_addr));
    sock_addr.sin_family = AF_INET;
    memcpy( &sock_addr.sin_addr.s_addr,
            host -> h_addr,
            host -> h_length );

    sock_addr.sin_port = htons(port);

    if( connect(sockfd, (struct sockaddr *) &sock_addr, sizeof(sock_addr)) == -1)
    {
        close(sockfd);
        return NULL;
    }

    if( write(sockfd, headers, strlen(headers) + 1) == -1)
    {
        close(sockfd);
        return NULL;
    }

    buffer = malloc( MAX_BUFFER_SIZE );
    tbuf = malloc( MAX_BUFFER_SIZE );

    if(buffer == NULL || tbuf == NULL)
    {
        return NULL;
    }

    int bytesloaded = 0;
    int readed;

    while( (readed = read(sockfd, tbuf, MAX_BUFFER_SIZE)) > 0 )
    {   

        if(bytesloaded + readed >= buf_size)
        {
            buf_size = buf_size + MAX_BUFFER_SIZE;  
            newbuf = realloc(buffer, buf_size);

            if(newbuf != NULL)
               buffer = newbuf; 
            else 
              return NULL;
        }
          memcpy(buffer + bytesloaded, tbuf, readed);
      bytesloaded += readed;
    }

    //printf("bytesreaded = %d and buffer len is %d\n", bytesloaded, strlen(buffer));
    free(tbuf);
    close(sockfd);

    return buffer;
}

, то:

char * domain = "www.google.com\0"; char * sheaders = "GET /images/srpr/logo3w.png HTTP/1.1\r\nHost:www.google.com\r\nConnection:close\r\n\r\n\n\0"; int port = 80; char * response = httpget(domain, port, sheaders);

1 Ответ

4 голосов
/ 25 марта 2012

Не использовать функции str* для произвольных данных.Они предназначены для работы со строками C, которые заканчиваются нулем.Двоичные данные (большинство графических форматов) могут содержать нули посередине.

Вы должны использовать memcpy / memmove, и вы должны полагаться на возвращаемое значение read, чтобы знать, сколько данныхты на самом деле получил.strlen для двоичных данных не имеет смысла.

Попробуйте заменить эту часть:

bytesloaded += readed;
strcat(buffer, tbuf);

на что-то вроде:

if (bytesloaded+readed >= buf_size) {
  // do the realloc now
}
memcpy(buffer+bytesloaded, tbuf, readed);
bytesloded += readed;

buffer + xxцелочисленный тип, значение которого меньше выделенного размера буфера) является указателем на x th символ в buffer.(Это арифметика указателей. Тип buffer имеет значение. В этом случае он недействителен, если x отрицателен.)
Вам необходимо выполнить перераспределение перед попыткой memcpy, иначе вы рискуетезапись за конец буфера.
memcpy здесь безопасно, потому что вы знаете, что buffer и tbuf не перекрываются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...