The intention of this post is to figure out how to implement a Keep-Alive timeout on a Boost ASIO based HTTP server.
There are 2 parts to this -
When the client has closed the connection
When the client connection is inactive
I believe, 1) above can be detected by setting the TCP_KEEPIDLE, TCP_KEEPCNT and TCP_KEEPINTVL options on the native socket handle.
What is the best way to detect 2) above?
I have tried setting the SO_RCVTIMEO and SO_SNDTIMEO on the native socket, but the server doesn't seem to close the connection at the end of the configured timeout interval.
Any pointers are much appreciated.
Thanks!
You want to detect the case when the client has not sent you anything for X amount of time. You can do this using a timer in Asio: How do I make the boost/asio library repeat a timer?
Either construct one timer object per client, or construct one global timer and check the last message received time for all clients every time the timer fires.
SO_RCVTIMEO won't help you, because when it expires the receive call returns EAGAIN or similar, and Asio will probably not do anything with this. Read about that here: SO_RCVTIME and SO_RCVTIMEO not affecting Boost.Asio operations
Related
I have a simple Client application (using QWebSocket) that wants to connect to my server application (i.e. QWebSocketServer).
When I open a connection to a webSocketServer that is down/unavailable, my webSocket fires a "disconnectd" signal after 30 sec.
This is good as it helps me to understand that the server is down/unavailable so I can retry or warn the user about the problem.
If the link between the client and server fails the same thing happens. i.e. after writing (sendBinaryMessage) to the webSocket causes the disconnected signal to be fired after 30 secs.
I would like to know what are the default timers in QWebSocket and how I can modify them?
Where can I find such information/documentation? The Qt documentation on webSockets does not mention this behaviour at all! Should I read the code or ...?!
Thanks in advance
I doubt that any of these timers are part of Qt; these timers exist as part of the underlying operating system's implementation of TCP/IP. A socket waiting for a connection to time out will eventually go bad if the remote end does not respond. Same if a sent data is not acknowledge after a reasonable amount of time.
Qt however does everything asynchronously and makes use of signals and slots to notify you when something has happened. This means that if you want to shorten a timeout the simplest way to do this is using a QTimer that runs in parallel to you QAbstractSocket, if the timer times out before the socket signals its response, you can then take appropriate action.
Failing that, there may be some socket options that allow you to set the various timeouts on your TCP Connection to your liking.
From QWebSocket:
This class was modeled after QAbstractSocket.
QAbstractSocket in turn inherits from QIODevice.
The documentation of these classes have some information about timeouts.
Specifically you can see the default of 30 seconds pop up here and there.
Another place to look at is QObject's documentation (QWebSocket inherits it). Perhaps by overriding QObject's timer-related virtual functions you can somehow get in between these mechanisms and perhaps change the timeout.
Sorry to not be of more help.
I have a server application written in C++. When a client connects, it creates a new thread for him. In that thread there is a BLOCKING reading from a socket. Because there is a possibility for a client to accidentally disconnect and left behind a thread still hanging on the read function, there is a thread that checks if the sockets are still alive by sending "heartbeat messages". The message consists of 1 character and is "ignored" by the client (it is not processed like other messages). The write looks like this:
write(fd, ";", 1);
It works fine, but is it really necessary to send a random character through the socket? I tried to send an empty message ("" with length 0), but it didn't work. Is there any better way to solve this socket checking?
Edit:
I'm using BSD sockets (TCP).
I'm assuming when you say, "socket, you mean a TCP network socket.
If that's true, then the TCP protocol gives you a keepalive option that you would need to ask the OS to use.
I think this StackOverflow answer gets at what you would need to do, assuming a BSDish socket library.
In my experience, using heartbeat messages on TCP (and checking for responses, e.g. NOP/NOP-ACK) is the easiest way to get reliable and timely indication of connectivity at the application layer. The network layer can do some interesting things but getting notification in your application can be tricky.
If you can switch to UDP, you'll have more control and flexibility at the application layer, and probably reduced traffic overall since you can customize the communications, but you'll need to handle reliability, packet ordering, etc. yourself.
You can set connection KEEPALIVE. You may have interests in this link: http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html
It is ok you create a thread for each new coming requests if it is only toy. In most of time, i use poll, that is non-blocking io, for performance improvement.
As far as I know Keep-alive on a TCP socket is helpful to know if the sockets aren't just opened and a connection is actually alive between the two sockets. So, I have a couple of questions I'd like to inquire regarding the usage of Keepalive in Winsocks2:
What happens when keep-alive option detects a dead socket?
How can I check if connection is alive or dead without actually using
the send and recv? If I have to use send and recv functions then
what's the point of using keep-alive in the first place?
What happens when keep-alive option detects a dead socket?
The connection is reset, and any reads or writes get a 'connection reset' error. Note that keepalive is off by default, and when enabled only operates at two-hour intervals by default.
How can I check if connection is alive or dead without actually using the send and recv?
You can't. TCP/IP is deliberately designed not to have a 'dial tone'. It works much better that way. This is a major reason why it has displaced all the prior protocols such as SNA that did.
If I have to use send and recv functions then what's the point of using keep-alive in the first place?
recv() won't tell you about a broken connection. It may just block forever. You can use read timeouts, but then you have to decide how much time is too much. Or, you can implement an application-level PING.
Keep alive detects if the server at the other end of the connection (or a physical link such as a network being down) has died before you send a message. Otherwise the disconnection is only detected when you actually try to send data, which if your connection is idle for some reason could take a long time.
connect is failing with WSAETIMEDOUT. That's fine but is there anyway to make the timeout period shorter? Maybe something like 2-3 seconds? Currently it seems to be something higher like 10 seconds.
OS is Windows, using Winsock with C++
Put the socket into non-blocking mode before calling connect(). When it returns with a WSAEWOULDBLOCK error, call select() with whatever timeout interval you want. If select() reports the socket becomes writable, the connection was successful. If select() reports a timeout instead, close the socket.
This has been asked before: WINSOCK - Setting a timeout for a connection attempt on a non existing IP?
No, it's handled by the IP stack. You'll have to start a timer and kill the connection if you need to change this functionality.
I am currently testing my network application in very low bandwidth environments. I currently have code that attempts to ensure that the connection is good by making sure I am still receiving information.
Traditionally I have done this by recording the timestamp in my ReadHandler function so that each time it gets called I know I have received data on the socket. With very low bandwidths this isn't sufficient because my ReadHandler is not getting called frequently enough.
I was toying around with the idea of writing my own completion condition function (right now I am using tranfer_at_least(1)) thinking it would get called more frequently and I could record my timestamp there, but I was wondering if there wasn't some other more standard way to go about this.
We had a similar issue in production: some of our connections may be idle for days, but we must detect if the remote is dead ASAP.
We solved it by enabling the TCP_KEEPALIVE option:
boost::asio::socket_base::keep_alive option(true);
mSocketTCP.set_option(option);
which had to be accompanied by new startup script that writes sensible values to /proc/sys/net/ipv4/tcp_keepalive_* which have very long timeouts by default (on LInux)
You can use the read_some method to get partial reads, and deal with the book keeping. This is more efficient than transfer_at_least(1), but you still have to keep track of what is going on.
However, a cleaner approach is just to use a concurrent deadline_timer. If the timer goes off before you are finished, then is taking too long and cancel whatever is going on. If not, just stop the timer and continue. Something like:
boost::asio::deadline_timer t;
t.expires_from_now(boost::posix_time::seconds(20));
t.async_wait(bind(&Class::timed_out, this, _1));
// Do stuff.
if (!t.cancel()) {
// Timer went off, abort
}
// And the timeout method
void Class::timed_out(error_code const& error)
{
if (error == boost::asio::error::operation_aborted) return;
// Deal with the timeout, close the socket, etc.
}
I don't know how to handle low latency of network from within application. Can you be sure if it's network latency, or if peer server or peer application busy and react slowly. Does it matter if it network/server/application quilt?
Even if you can discover network latency and find it's big, what are you going to do?
You can not improve the situation.
Consider other critical case which is a subset of what you're trying to handle - network is down (e.g. you disconnect cable from your machine). Since it a subset of your problem you want to handle it too.
Let's examine the network down effect on active TCP connection.How can you discover your active TCP connection is still alive? Calling send() will success, but it merely says that the message queued in TCP outgoing queue in kernel. TCP stack will try to send it, but since TCP ACK won't be sent back, TCP stack on your side will try to resend it again and again. You can see your message in netstat output (Send-Q column).
I'm aware of the following ways to deal with it:
One standard way is TCP keep alive proposed #Cubby.
Another way is to implement Keep Alive mechanism. Send Keep Alive req message and peer is obligated to send back Keep Alive ack message.
If you don't receive ack message after predefined timeout, try to send Keep Alive req N more times (e.g. N=2). If still no success, close the socket and open it again. If peer server is not available you'll not be abable to open connection, since TCP 3 way handshake requires peer to respond.