Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

KeepAlive with WCF and TCP?

I have a Windows Service hosting an advanced WCF service that communicates over TCP(netTCP) with protobuf.net, some times also with certificates.

The receiveTimeout is set to infinite to never drop the connection due to inactivity. But from what I understand the connection could be dropped anyway so I have created a simple two way keepalive service method that the client is calling every 9 min to keep the connection alive. It's very important that the connection never breaks.

Is this the correct way? Or could I simply remove my keep live because the receiveTimout is set to infinite?

Edit : Current app.config for WCF service : http://1drv.ms/1uEVKIt

like image 387
Banshee Avatar asked Nov 04 '14 10:11

Banshee


People also ask

Is keep alive TCP?

TCP keepalive Transmission Control Protocol (TCP) keepalives are an optional feature, and if included must default to off. The keepalive packet contains no data.

How does a keepalive connection work?

The KeepAlive mechanism does this by sending low-level probe messages to see if the other side responds. If it does not respond to a certain number of probes within a certain amount of time, then it assumes the connection is dead and the process using the socket will then detect this through an error indication.

How do I know if keepalive is enabled?

All modern browsers use persistent connections as long as the server has Keep-Alive enabled. In order to check if your pages are delivered with a Keep-Alive header, you can use the HTTP Header Checker tool. This will display the Connection: Keep-Alive field if the HTTP Keep-Alive header is enabled.

What is client side keepalive?

The Client Keep-Alive mode enables the Citrix ADC appliance to process multiple requests and responses using the same socket connection. The feature keeps the connection between the client and the appliance (client-side connection) open even after the server closes the connection with the appliance.


1 Answers

No. This is widely misunderstood, and unfortunately there is much misinformation out there.

First, "Infinite" is a sort of semi-valid value. There is are two special config serializers that convert "Infinite" to either TimeSpan.MaxValue or int.MaxValue (so they're not really "infinite" anyways), but not everything in WCF seems to recognize this. So it's always best to specify your timeouts explicitly with time values.

Second, you don't need a "keepalive" method in your service, since WCF provides what's called a "reliable session". If you add <reliableSession enabled="true" /> then WCF will provide it's own keep alive mechanism through "infrastructure messages".

By having your own "keepalive" mechanism, you're effectively doubling the load on your service and you can actually create more problems than it solves.

Third, when using a reliable session, you use the inactivityTimeout setting of reliableSession. This does two things. First, it controls how frequently infrastructure (keepalive) messages are sent. They are sent at half the timeout value, so if you set it to 18 minutes, then they will be sent every 9 minutes. Secondly, if no infrastructure or operation messages (ie messages that are part of your data contract) are received within the inactivity timeout, the connection is aborted because there has likely been a problem (one side has crashed, there's a network problem, etc..).

receiveTimeout is the maximum amount of time in which no operation messages can be received before the connection is aborted (the default is 10 minutes). Setting this to a large value (Int32.MaxValue is somewhere in the vicinity of 24 days) keeps the connection tacked up, setting inactivityTimeout to a smaller value (again, the default is 10 minutes) (to a time that is smaller than 2x the maximum amount of time before network routers will drop a connection from inactivity) keeps the connection alive.

WCF handles all this for you. You can then simply subscribe to the Connection Aborted messages to know when the connection is dropped for real reasons (app crashes, network timeouts, clients losing power, etc..) and allows you to recreate the connections.

Additionally, if you don't need ordered messages, set ordered="false", as this greatly reduces the overhead of reliable sessions. The default is true.

Note: You may not receive a connection aborted event until the inactivityTimeout has expired (or you try to use the connection). Be aware of this, and set your timeouts accordingly.

Most recommendations on the internet are to set both receiveTimeout and inactivityTimeout to Infinite. This has two problems, first infrastructure messages don't get sent in a timely manner, so routers will drop the connection... forcing you to do your own keepalives. Second, the large inactivity timeout means it won't recognize when a connection legitimately drops, and you have to rely on on that ping aborting to know when a failure occurs. This is all completely unnecessary, and can in fact even make your service even more unreliable.

See also this: How do I correctly configure a WCF NetTcp Duplex Reliable Session?

like image 107
Erik Funkenbusch Avatar answered Oct 15 '22 08:10

Erik Funkenbusch