When I am using this Python script to send a request to my server:
import requests as r
url = "http://localhost:8070/"
response = r.get(url=url)
It sends the following request:
GET / HTTP/1.1
Host: localhost:8070
User-Agent: python-requests/2.27.1
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
If I understand it correctly, Connection: keep-alive
means that I should not close the client-socket, because the client could use it again.
But if I do not close the client-socket, the Python script just gets stuck until I close the socket. Is there another way to indicate that the request is complete so pythons requests understands it?
If I try to send the request to any other server, the script almost immediately finishes. My guess would be to timeout the client after a few milliseconds e.g. by using select like this:
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 1000;
select_ret = select(this->_maxfds 1, &this->_readfds, &this->_writefds, NULL, &timeout);
And now I would just close the client-socket after select returns 0:
if (select_ret == 0) {
close(client_socket);
}
Is that a valid approach, or am I missing something?
I am sending the response like this:
char *response = "HTTP/1.1 200 Ok\r\n\r\n";
send(this->_client_socket, response, strlen(response), 0)
BUT this does not terminate the python script. The python script still hangs after I execute this line of code. It only finishes when I close the socket on my side.
So how would I determine if I should close it or not? As I already said my approach was to use a timeout in case no data is getting written in to the socket from the client side.
CodePudding user response:
Your server's response is incomplete.
Your understanding of Connection: keep-alive
in the request is correct. However, there is no Content-Length
or Transfer-Encoding: chunked
header present in your response, so the only way the client has to know when the response is finished is to wait for the socket connection to be closed on the server side. Read the rules outlined in RFC 2616 Section 4.4 and RFC 7230 Section 3.3.3 of the HTTP 1.1 protocol spec.
Try something more like this instead:
const char *response = "HTTP/1.1 200 Ok\r\nContent-Length: 0\r\n\r\n";
send(this->_client_socket, response, strlen(response), 0)
CodePudding user response:
But if I do not close the client-socket, the python script just gets stuck until I close the socket
What do you mean 'gets stuck' Does it hang waiting for a response from the server? Does the server send a response but the client never receives it? Does the server never send a response and the client is expecting a response?
Is there another way to indicate that the request is complete so pythons requests understands it?
Yes, send a response to the client from the server. The response indicates how the request was completed and if there were any errors. Once the client receives the response it can then close the socket.
Now if you don't want to keep the connection alive, you can simply send connection:close This will simply tell the server to close the socket after the request is completed.
As for when you should close a socket on keep-alive, it's completely up to your client to disconnect when it needs to. My browser can send keep-alive to a server but I can close the browser at any point. The client can also send parameters to the server explicitly stating how long to keep the connection alive for , see here keep-alive parameters
When should your server know to close the client's socket on keep-alive?
Simple, it doesn't need to know and it doesn't care to know. It's up to your client to close the connection on keep-alive. The server receives a request and sends a response. The client dictates its further actions based on the response. If your client is hanging this is a bug in your client code. This is assuming you coded your server correctly.