1

I am using TCP as a mechanism for keep alive here is my code:

Client

TcpClient keepAliveTcpClient = new TcpClient();
keepAliveTcpClient.Connect(HostId, tcpPort);

//this 'read' is supposed to blocked till a legal disconnect is requested
//or till the server unexpectedly dissapears
int numberOfByptes = keepAliveTcpClient.GetStream().Read(new byte[10], 0, 10);

//more client code...

Server

TcpListener _tcpListener = new TcpListener(IPAddress.Any, 1000);
_tcpListener.Start();
_tcpClient = _tcpListener.AcceptTcpClient();
Tracer.Write(Tracer.TraceLevel.INFO, "get a client");

buffer = new byte[10];
numOfBytes = _tcpClient.GetStream().Read(buffer, 0, buffer.Length);
if(numOfBytes==0)
{
    //shouldn't reach here unless the connection is close...
}

I put only the relevant code... Now what that happens is that the client code is block on read as expected, but the server read return immediately with numOfBytes equals to 0, even if I retry to do read on the server it return immediately... but the client read is still block! so in the server side I think mistakenly that the client is disconnected from the server but the client thinks it connected to the server... someone can tell how it is possible? or what is wrong with my mechanism?

Edit: After a failure I wrote to the log these properties:

_tcpClient: _tcpClient.Connected=true

Socket: (_tcpClient.Client properties)

_tcpClient.Client.Available=0
_tcpClient.Client.Blocking=true
_tcpClient.Client.Connected=true
_tcpClient.Client.IsBound=true

Stream details

_tcpClient.GetStream().DataAvailable=false;
ilay zeidman
  • 2,654
  • 5
  • 23
  • 45
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Jan 27 '15 at 16:17
  • Whats `buffer.Length`? – usr Jan 27 '15 at 16:20
  • @usr I added the buffer initialization... its size is 10 – ilay zeidman Jan 27 '15 at 16:23
  • OK, this cannot happen during under normal circumstances. Think out of the box. Are you connecting to the right endpoint? Kill the server to make sure. Are you closing the _tcpClient accidentally? Btw, TCP keepalive cannot be used to quickly or reliably detect disconnectedness. Maybe this entire question is moot. – usr Jan 27 '15 at 16:32
  • I tell you what, this mechanism work most of the time but 1 of 20 connections behave like I described above. I am sure I connect to the right endpoint I can see it in the logs and I am sure that I am not closing the _tcpClient accidentally. It is really really weird behavior that is why I asked the question... maybe someone had similar experience.... – ilay zeidman Jan 27 '15 at 16:38
  • When the network has a problem the two machines are not notified. They will not find out until TCP keepalive happens after hours (or never depending on the OS). – usr Jan 27 '15 at 16:58
  • In my mechanism the client sends "a" to the server every 10 seconds to ensure the TCP connection is still there so the server is run in loop and check every time to see it got "a". – ilay zeidman Jan 27 '15 at 17:15
  • Maybe something that will give clue: it happens only when 10 or more clients connect the server the same time(the server listen to 10 or more ports)... – ilay zeidman Jan 27 '15 at 17:20
  • You haven't provided enough code to allow an answer. The server will see a 0-byte read-completion only if the client shuts down the socket. So, for sure the client is shutting down the socket prematurely. But lacking [a good, concise, complete code example](http://stackoverflow.com/help/mcve), it's not possible to provide a useful answer. – Peter Duniho Jan 28 '15 at 04:53

4 Answers4

2

Even when correctly implemented, this approach will only detect some remote server failures. Consider the case where the intervening network partitions the two machines. Then, only when the underlying TCP stack sends a transport level keep-alive will the system detect the failure. Keepalive is a good description of the problem. [Does a TCP socket connection have a “keep alive”?] 2 is a companion question. The RFC indicates the functionality is optional.

The only certain way to reliably confirm that the other party is still alive is to occasionally send actual data between the two endpoints. This will result in TCP promptly detecting the failure and reporting it back to the application.

Community
  • 1
  • 1
Pekka
  • 3,529
  • 27
  • 45
2

Maybe something that will give clue: it happens only when 10 or more clients connect the server the same time(the server listen to 10 or more ports).

If you're writing this code on Windows 7/8, you may be running into a connection limit issue. Microsoft's license allows 20 concurrent connections, but the wording is very specific:

[Start->Run->winver, click "Microsoft Software License Terms"]

3e. Device Connections. You may allow up to 20 other devices to access software installed on the licensed computer to use only File Services, Print Services, Internet Information Services and Internet Connection Sharing and Telephony Services.

Since what you're doing isn't file, print, IIS, ICS, or telephony, it's possible that the previous connection limit of 10 from XP/Vista is still enforced in these circumstances. Set a limit of concurrent connections to 9 in your code temporarily, and see if it keeps happening.

lorimer
  • 121
  • 4
2

The way I am interpretting the MSDN remarks it seems that behavior is expected. If you have no data the Read the method returns.

With that in mind I think what I would try is to send data at a specified interval like some of the previous suggestions along with a "timeout" of some sort. If you don't see the "ping" within your designated interval you could fail the keepalive. With TCP you have to keep in mind that there is no requirement to deem a connection "broken" just because you aren't seeing data. You could completely unplug the network cables and the connection will still be considered good up until the point that you send some data. Once you send data you'll see one of 2 behaviors. Either you'll never see a response (listening machine was shutdown?) or you'll get an "ack-reset" (listening machine is no longer listening on that particular socket)

https://msdn.microsoft.com/en-us/library/vstudio/system.net.sockets.networkstream.read(v=vs.100).aspx

Remarks: This method reads data into the buffer parameter and returns the number of bytes successfully read. If no data is available for reading, the Read method returns 0. The Read operation reads as much data as is available, up to the number of bytes specified by the size parameter. If the remote host shuts down the connection, and all available data has been received, the Read method completes immediately and return zero bytes.

Brian Booth
  • 727
  • 1
  • 6
  • 10
-2

As I can see you are reading data on both sides, server and client. You need to write some data from the server to the client, to ensure that your client will have something to read. You can find a small test program below (The Task stuff is just to run the Server and Client in the same program).

class Program
{
    private static Task _tcpServerTask;
    private const int ServerPort = 1000;

    static void Main(string[] args)
    {
        StartTcpServer();
        KeepAlive();

        Console.ReadKey();
    }

    private static void StartTcpServer()
    {
        _tcpServerTask = new Task(() =>
        {
            var tcpListener = new TcpListener(IPAddress.Any, ServerPort);
            tcpListener.Start();

            var tcpClient = tcpListener.AcceptTcpClient();
            Console.WriteLine("Server got client ...");

            using (var stream = tcpClient.GetStream())
            {
                const string message = "Stay alive!!!";

                var arrayMessage = Encoding.UTF8.GetBytes(message);
                stream.Write(arrayMessage, 0, arrayMessage.Length);   
            }

            tcpListener.Stop();
        });

        _tcpServerTask.Start();
    }

    private static void KeepAlive()
    {
        var tcpClient = new TcpClient();
        tcpClient.Connect("127.0.0.1", ServerPort);
        using (var stream = tcpClient.GetStream())
        {
            var buffer = new byte[16];
            while (stream.Read(buffer, 0, buffer.Length) != 0)
                Console.WriteLine("Client received: {0} ", Encoding.UTF8.GetString(buffer));
        }
    }
}
  • In my mechanism the client sends "a" to the server every 10 seconds to ensure the TCP connection is still there so the server is run in loop and check every time to see it got "a". – ilay zeidman Jan 27 '15 at 17:53
  • 1
    "You need to write some data from the server to the client, to ensure that your client will have something to read" -- this may be true if the OP wants the client to read actual data. But the return value of 0 from the `Read()` method means something very specific (the remote endpoint has shutdown the socket), and is not due to an absence of data per se. So writing data to the socket isn't going to help. – Peter Duniho Jan 28 '15 at 04:51