当尝试重用 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"
写一个小的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"