我尝试构建一个多线程服务器,这样当有多个并发请求时,服务器可以同时处理它们。但是,我的代码仍然需要等待第一个请求完成才能执行
我尝试构建一个多线程服务器,这样当有多个并发请求时,服务器可以同时处理它们。但是,我的代码仍然需要等待第一个请求完成后才能开始第二个请求。
下面是我的代码
int main() {
//server startup
WSADATA wsaData;
int server_start = WSAStartup(MAKEWORD(2,2),&wsaData);
if(server_start) {
cout<<"Error at startup socket!"<<endl;
return 0;
}
//server init
SOCKET server_socket = socket(AF_INET, SOCK_STREAM, 0);
if(!server_socket) {
printf("socket function failed with error: %u\n", WSAGetLastError());
return 0;
}
sockaddr_in server_address;
memset(&server_address,0,sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_port = htons(PORT);
//server binding
if(bind(server_socket,(sockaddr*)&server_address,sizeof(server_address))) {
cout<<"socket function fail at binding"<<endl;
return 0;
}
//server listening
if(listen(server_socket,5) == -1) {
cout<<"Fail at listening"<<endl;
return 0;
}
cout<<"Server listening at port "<<PORT<<endl;
while(true) {
//init client data
sockaddr_in client_address;
socklen_t client_address_len = sizeof(client_address);
//server accept
SOCKET client_socket = accept(server_socket,(sockaddr*)&client_address,&client_address_len);
cout<<"Client socket init : "<<client_socket<<endl;
if(!client_socket) {
cout<<"Error when accepting connection"<<endl;
continue;
}
cout<<"Accepeted connection from "
<<inet_ntoa(client_address.sin_addr)<<":"<<ntohs(client_address.sin_port)<<endl;
thread(handle_connection, client_socket).detach();
}
WSACleanup();
return 0;
}
int handle_connection(SOCKET client_socket) {
cout<<"Thread with id "<<this_thread::get_id()<<" with socket "<<client_socket<<endl;
//handle HTTP request
char buffer[BUFFER_SIZE];
memset(buffer,0,BUFFER_SIZE);
SSIZE_T bytes_recived = recv(client_socket,buffer,BUFFER_SIZE,0);
if(bytes_recived <= 0) {
cout<<"Failed to read the request!"<<endl;
return 0;
}
//parse request
string request(buffer,bytes_recived);
SSIZE_T first_space = request.find(' ');
string method = request.substr(0, first_space);
SSIZE_T second_space = request.find(' ', first_space + 1);
string path = request.substr(first_space+1, second_space-first_space-1);
cout<<"Received "<<method<< " request for " <<path<<endl;
if(method == "GET") {
//simulate heavy task with delay
chrono::system_clock::time_point delay_time = chrono::system_clock::now() + chrono::seconds(3);
while(delay_time > (chrono::system_clock::now())) {}
cout<<"Done delay!"<<endl;
string response = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<html><body><h1>Hello World!</h1></body></html>";
send(client_socket,response.c_str(),response.length(),0);
} else {
std::string response = "HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\n\r\n<html><body><h1>404 Not Found</h1></body></html>";
send(client_socket, response.c_str(), response.length(), 0);
}
closesocket(client_socket);
return 0;
}
如果我向服务器发出 3 个 GET 请求,第一个请求将需要 3 秒,第二个请求需要 6 秒,第三个请求需要 9 秒。难道不应该 thread
单独处理连接吗?为什么另一个线程仍然依赖于第一个连接?任何建议都将不胜感激
首先,由于您没有正确接收和解析 HTTP 请求,因此此代码根本无法成为可行的 HTTP 服务器。
但是,除此之外,尽管您可以处理多个连接(尽管使用 分离 线程值得怀疑),但 HTTP 1.x 连接根本无法一次处理超过 1 个请求。这就是 HTTP 协议的工作方式,至少在具有多路复用功能的 HTTP/2 之前是这样的。对于 HTTP 1.x,要并行运行多个请求,您需要多个连接,但浏览器往往会池化它们的连接,并且不能保证一次使用多个连接到同一服务器,并且您不能强迫浏览器这样做。
还有一点需要考虑 - 即使您确实同时有多个连接,您的客户端线程也会有一个繁忙的循环,不会为其他线程提供 CPU 时间。您应该使用 std::this_thread::sleep_for()
or std::this_thread::sleep_until()
来使调用线程进入睡眠状态,同时允许其他线程有机会运行,例如:
if(method == "GET") {
//simulate heavy task with delay
std::this_thread::sleep_for(chrono::seconds(3));
...
}