What is the best way to implement a heartbeat in C++ to check for socket connectivity?
Asked Answered
K

5

10

Hey gang. I have just written a client and server in C++ using sys/socket. I need to handle a situation where the client is still active but the server is down. One suggested way to do this is to use a heartbeat to periodically assert connectivity. And if there is none to try to reconnect every X seconds for Y period of time, and then to time out.

Is this "heartbeat" the best way to check for connectivity?

The socket I am using might have information on it, is there a way to check that there is a connection without messing with the buffer?

Kathrinkathrine answered 30/1, 2009 at 15:32 Comment(0)
C
14

If you're using TCP sockets over an IP network, you can use the TCP protocol's keepalive feature, which will periodically check the socket to make sure the other end is still there. (This also has the advantage of keeping the forwarding record for your socket valid in any NAT routers between your client and your server.)

Here's a TCP keepalive overview which outlines some of the reasons you might want to use TCP keepalive; this Linux-specific HOWTO describes how to configure your socket to use TCP keepalive at runtime.

It looks like you can enable TCP keepalive in Windows sockets by setting SIO_KEEPALIVE_VALS using the WSAIoctl() function.

If you're using UDP sockets over IP you'll need to build your own heartbeat into your protocol.

Catalase answered 30/1, 2009 at 15:39 Comment(4)
This is a very bad solution. TCP keepalives are very inflexible, providing you with no good way to control how often they are sent. If you have control over both sides, as the OP does, it's much better to just design a connection liveness test into your own protocol.Slicker
Hey, something's up with the link - tldp.­org/­HOWTO/­TCP-­Keepalive-­HOWTO/­overview.­html seems brokenZincograph
@DavidSchwartz Just to elaborate on your advice against TCP keepalives, because this is rarely discussed (hence the recommendations by people who have never used it): There are in fact parameters that can be changed, like "keepalive time", "keepalive interval", "number of keepalive probes", but these settings apply systemwide, not per socket, i.e. they are not suitable for more than one use case on the same system. Plus, the default settings are horrible in most cases, like a keepalive time of 2 hours. And it is not possible to change them in an OS agnostic way.Histolysis
As of Windows 10 (version 1709) more parameters (TCP_KEEPIDLE, TCP_KEEPINTVL) are supported: learn.microsoft.com/en-us/windows/win32/winsock/…Radbun
S
6

Yes, this heartbeat is the best way. You'll have to build it into the protocol the server and client use to communicate.

The simplest solution is to have the client send data periodically and the server close the connection if it hasn't received any data from the client in a particular period of time. This works perfectly for query/response protocols where the client sends queries and the server sends responses.

For example, you can use the following scheme:

  1. The server responds to every query. If the server does not receive a query for two minutes, it closes the connection.

  2. The client sends queries and keeps the connection open after each one.

  3. If the client has not send a query for one minute, it sends an "are you there" query. The server responds with "yes I am". This resets the server's two minutes timer and confirms to the client that the connection is still available.

It may be simpler to just have the client close the connection if it hasn't needed to send a query for the past minute. Since all operations are initiated by the client, it can always just open a new connection if it needs to perform a new operation. That reduces it to just this:

  1. The server closes the connection if it hasn't received a query in two minutes.

  2. The client closes the connection if it hasn't needed to send a query in one minute.

However, this doesn't assure the client that the server is present and ready to accept a query at all times. If you need this capability, you will have to implement an "are you there" "yes I am" query/response into your protocol.

Slicker answered 24/9, 2012 at 18:24 Comment(1)
I would mark your post as the answer if it was me asking the question.Malissamalissia
D
2

If the other side has gone away (i.e. the process has died, the machine has gone down, etc.), attempting to receive data from the socket should result in an error. However if the other side is merely hung, the socket will remain open. In this case, having a heartbeat is useful. Make sure that whatever protocol you are using (on top of TCP) supports some kind of "do-nothing" request or packet - each side can use this to keep track of the last time they received something from the other side, and can then close the connection if too much time elapses between packets.

Note that this is assuming you're using TCP/IP. If you're using UDP, then that's a whole other kettle of fish, since it's connectionless.

Dilator answered 30/1, 2009 at 15:42 Comment(0)
G
1

Ok, I don't know what your program does or anything, so maybe this isn't feasible, but I suggest that you avoid trying to always keep the socket open. It should only be open when you are using it, and should be closed when you are not.

If you are between reads and writes waiting on user input, close the socket. Design your client/server protocol (assuming you're doing this by hand and not using any standard protocols like http and/or SOAP) to handle this.

Sockets will error if the connection is dropped; write your program such that you don't lose any information in the case of such an error during a write to the socket and that you don't gain any information in the case of an error during a read from the socket. Transactionality and atomicity should be rolled into your client/server protocol (again, assuming you're designing it yourself).

Grogram answered 30/1, 2009 at 15:52 Comment(9)
What's the advantage of closing and re-opening the socket all the time?Dilator
You aren't dependent on or wasting external resources. Again, I don't know what the program does, but most programs spend more time waiting for user input than they do writing or reading to/from a network. There's no need for the socket to be open at those times.Grogram
Meh. You're adding extra code and extra work to save yourself one socket. Web browsers used to work this way but it was too slow to keep dropping and re-creating connections. That's why keepalive was added in HTTP/1.1.Dilator
And does any modern browser keep the socket open between user requests? No, it does not. Keepalive was added because getting everything involved in a single web page really constitutes a single request and it's therefore better to keep using the same socket.Grogram
Also, I think we disagree as to what "extra code and extra work" means. I personally think a program that tries to keep a socket open all the time no matter what is going pretty deep into the realm of "extra code and extra work".Grogram
Whether or not you keep a TCP/IP connection open depends entirely on what the application is doing.Haematogenesis
I work on a client-server database product. We have a concept of a database connection, which has an underlying TCP connection. In our world, "trying to keep a socket open" is simply not closing it, and closing it between requests would be extra work. I think I'm assuming that paradigm...Dilator
(cont). Applications that use a different paradigm might benefit from your suggestion. I hereby revoke my "Meh". :-)Dilator
@17 of 26. You're right. I'm making the assumption that the program is user interactive rather than continuous processing. @Graeme: You're also right, see my comment to @17. Different paradigms and all that. :)Grogram
F
0

maybe this will help you, TCP Keepalive HOWTO or this SO_SOCKET

Fushih answered 30/1, 2009 at 15:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.