c++ 为什么在接收所有Content-Length之前接收块?

hts6caw3  于 2022-11-27  发布在  其他
关注(0)|答案(1)|浏览(118)

我正在尝试用c++构建一个http服务器。因此,在我决定如何提取body实体的条件中,是否存在内容长度?下面是我如何使用Content-Length提取body的最小代码:

req_t *Webserver::_recv(int client_fd, bool *closed)
{
    string req;
    static string rest;
    // string extracted_req;
    char buff[1024];

    // while (true) {
    // std::cout << "client_fd: " << client_fd << std::endl;
    int n = recv(client_fd, buff, 1024, 0);
    // std::cout << "n: " << n << std::endl;
    if (n == -1)
    {
        _set_error_code("500", "Internal Server Error");
        return NULL;
    }
    if (n == 0)
    {
        *closed = true;
        return NULL;
    }
    buff[n] = '\0';
    req += buff;
    req_t *extracted_req = _extract_req(client_fd, req, rest, closed);
    return extracted_req;
}

 ...
 else if (headers.find("Content-Length") != string::npos) {
    string body = extract_body_len(client_fd, rest_of_req, content_length);
}

req_t是一个简单的结构体,它包含三个字符串status_lineheadersbody
第一次
现在,问题是我已经测试了不同大小的正文实体(8MB,1.9MB,31 MB)的请求,并且一直没有收到整个正文(根据内容长度),模式如下:

  • recv继续阅读所有1024字节,直到total更接近len,然后它开始读取更小的数字。直到totallen之间的差大约为400...600字节,然后recvtotal == len之前的某个点处阻塞(没有更多要读取的)。

这真的让我很困惑,我尝试了不同的api客户端(postman,insonomia),但结果相同,我怀疑可能Content-Length不是那么准确but it obviously should be,你认为问题是什么,为什么我接收或阅读的少于Content-Length

oyjwcjzk

oyjwcjzk1#

int n = recv(client_fd, buff, 1024, 0);

上面的代码似乎假设这个recv调用只返回HTTP请求的头部,一个字节也不多,一个字节也不少。
不幸的是,你在网络编程的教科书中找不到任何东西能给你任何这样的保证。
您唯一的保证(假设没有套接字级别的错误)是recv()将返回一个介于1和1024之间的值,表示套接字上已经接收了多少字节,或者在它阻塞和等待的第一个数据包中到达了多少字节。
使用一个完整的HTTP请求示例,如下所示:

POST /cgi-bin/upload.cgi HTTP/1.0<CR><LF>
Host: www.example.com<CR><LF>
Content-Type: application/octet-stream<CR><LF>
Content-Length: 4000<CR><LF>
<CR><LF>
[4000 octets follow]

当您的Web浏览器或模拟浏览器发送此请求时,此recv调用可以返回1到1024之间的任何值(网络错误除外)。
这意味着此recv调用可以提供以下范围内的任何内容:

  • 返回值1,并只将字母“P”放入buff
  • 返回值1024,并将整个HTTP头加上请求的HTTP内容部分的初始部分放入缓冲区,以产生总共1024个字节。

所示的逻辑完全不能正确处理所有这些可能性,这就是它失败的原因。它需要重新实现,几乎是从头开始,使用正确的逻辑。

相关问题