【问题标题】:read() are not reading the complete http responseread() 没有读取完整的 http 响应
【发布时间】:2012-03-25 17:15:01
【问题描述】:

我开始在 C 编程语言中使用套接字。我正在尝试发出一个简单的 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);

【问题讨论】:

    标签: c sockets


    【解决方案1】:

    不要对任意数据使用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 + x(x 是一个整数类型,其值小于分配的缓冲区大小)是指向buffer 中的xth 字符的指针。 (这是指针运算。buffer 的类型很重要。在这种情况下,如果x 为负数,则无效。)
    您需要在尝试 memcpy 之前执行重新分配,否则您可能会写到缓冲区末尾。
    memcpy 在这里是安全的,因为您知道 buffer 和 tbuf 不会重叠.

    【讨论】:

    • 非常感谢。你可以给我一个例子吗?我已经尝试过了,但是memcpy()/memmove() 没有像strcat() 这样连接字符串,那么,在缓冲区中我只有最后一个值作为参数传递。
    • 添加了一个关于如何做到这一点的变体。
    • :再次感谢。好吧,我用memcpy(buffer + bytesloaded, tbuf, readed); 替换,但它只复制HTTP 标头和�PNG\n 如何解决这个问题?查看我的代码更新。
    • 致 OP:您没有检查 write() 的返回值。它应该与 read() 类似。您还应该找到一种方法,不仅可以将指向结果缓冲区的指针返回给调用者,还可以返回它的长度。
    • @wildplasser:我将创建一个新变量并将缓冲区长度存储在其上。但是我如何检查 write() 大小?我检查它是否不返回-1(错误)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多