当尝试重用 HTTP 连接来处理 Keep-Alive header 时,recv 被从客户端读取第二个请求阻止

When trying to reuse an HTTP connection to process the Keep-Alive header, recv is blocked by reading the second request from the client

写一个小的http服务器,我要搞定"Connection: keep-alive"header。在此之前,我使用标准的请求处理模型:为一个请求打开一个连接,然后进行处理,发送一个响应,然后关闭连接。但是“保持活动状态”允许您 re-use 连接。问题是,我该怎么做?我应该使用什么算法?

我尝试这样做:使用 accept 打开连接 -> 使用 recv 从客户端套接字读取数据 -> 处理请求 -> 使用 send 发送响应。这个循环一直持续到 recv returns a value = 0,并且在退出循环时连接被关闭。但问题是,在循环的第二次迭代中,在处理完第一个请求后,recv 被阻塞了。请告诉我哪一步错了。

    for(;;)
        {
          client *current = client::listen_port(cone.get_socket());//called here to accept
          httpHandler worker(current);//this class handles requests, we pass a pointer to the class object in it, which contains information about the client
          for(;;)
          {
              httpParser* temp = new httpParser(current->get_client());// recv is called and the httpParser class parses the request
              if (temp->get_recvByte() > 0)
                worker.handle(temp);//if recv returned something, we process the request and respond to it
              if (temp->get_recvByte() == 0)
                  break;
              if (temp->get_recvByte())
                  std::cout << "error";
              delete temp;
          }
        }

此构造函数形成 header

   heading::heading(const int content_size, const std::string &file)
{
    head = "HTTP/1.1 200 OK\r\n";

    std::string Content_Type, Content_Length;
    std::string extension = file.substr(file.find(".") + 1);

    if (extension == "png" || extension == "gif")
        Content_Type = "Content-Type: image/apng\r\n";
    else if(extension == "jpg")
        Content_Type = "Content-Type: image/jpeg\r\n";
    else
        Content_Type = "Content-Type: text/html\r\n";
    Content_Length = "Content-Lenght: " + std::to_string(content_size) + "\r\n";
    head = head + "Server: Cone \r\n" + Content_Type + Content_Length + "Connection: keep-alive\r\n\r\n";
}

处理函数

void httpHandler::handle(httpParser *temp)
{
    parser = temp;
    if (parser->get_type() == HEAD)
    {
        heading head;
        send(newclient->get_client(), head.get_head().c_str(), head.get_head().length(), 0);
        return;
    }
    if (parser->get_type() == UNKNOWN)
        send(newclient->get_client(), heading::error404().c_str(), heading::error404().length(), 0);

    if (!parser->get_dynamic())
        static_handle();

    else
        dynamic_handle();
    parser = nullptr;
}

静态内容处理

void httpHandler::static_handle()
{
    std::string buffer; 
    std::ifstream file(getenv("path") + parser->get_file(), std::ifstream::binary); 
    if (file)
     {
         auto const size{file.tellg()}; 
         file.seekg(0); 
         char current;
         buffer.reserve(size);
         while(file.get(current)) //читаем файл
             buffer.push_back(current);
         heading head(buffer.length(), parser->get_file());
         buffer = head.get_head() + buffer;  заголовок к буферу
         send(newclient->get_client(), buffer.c_str(), buffer.length(), 0); 
      }
      else
         send(newclient->get_client(), heading::error404().c_str(), heading::error404().length(), 0);

     file.close();
}

解析器

httpParser::httpParser(int client_d)
{
    char buffer[req_buff_size];
    std::cout << "Calling recv() on socket " << client_d << std::endl;
    recvByte = recv(client_d, buffer,req_buff_size - 1, 0); // получаем сообщение из сокета
    if (recvByte > 0)
    {
        buffer[recvByte] = '[=16=]';
        reqest = buffer;
        std::cout << reqest <<std::endl; // для тестов
        if (recvByte < 0)
           throw std::invalid_argument( "error recv\n" );

        if (reqest.find("GET") == 0)
        {
          type = GET;
          GET_parse();
        }
          else if (reqest.find("POST") == 0)
        {
          type = POST;
          POST_Parse();
        }
        else if (reqest.find("HEAD") == 0)
          type = HEAD;
        else
          throw std::invalid_argument( "invalid REQ\n" );

        requestedFile();
    }
}

连接在客户端析构函数中关闭

你有:

"Connection: keep-alive\n\n";

应该是:

"Connection: keep-alive\r\n";

同样,正斜杠看起来也不正确

"Server: Cone /r/n"

应该是:

"Server: Cone\r\n"