• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 973
  • Last Modified:

c# / vs 2005: tcp keep alive

I'm using c# under vs 2005 in vista. i have a serial to Ethernet adapter that I'm using to control a serial device via tcp socket programming. the device is set to issue a keep-alive message every 15 seconds.

The method in the code window is the one that's called by BeginReceive. For positive length messages it handles them normally. Zero length messages should indicate keep-alive messages from the adapter.

The problem I'm having is with the zero-length messages. After the last interaction has completed, everything sits quietly for 15 seconds; then a zero length message shows up. If I include the line following "*** reset callback" then at once I'm in an infinite loop of getting zero-length messages.

I'm using Wireshark to sniff the network. So far as I can tell, these zero length messages are not coming from the adapter but seem to be coming from within .NET itself.

If I exclude the reset callback, then I get the zero-length message just once.

Ideas?
static void ReceiveData(IAsyncResult iar) {
    Encoding enc = Encoding.ASCII;
    Socket remote = (Socket)iar.AsyncState;
    int rcvlngth = remote.EndReceive(iar);
    if (rcvlngth > 0) {
        string rcvd = enc.GetString(data, 0, rcvlngth);
        Console.WriteLine(rcvlngth.ToString() + ": " + rcvd);
        remote.BeginReceive(data, 0, data.Length, SocketFlags.None, new AsyncCallback(ReceiveData), remote);
    }
    if (rcvlngth <= 0) {
        Console.WriteLine("hit zero length message");
        // *** reset callback
        remote.BeginReceive(data, 0, data.Length, SocketFlags.None, new AsyncCallback(ReceiveData), remote);
    }
}

Open in new window

0
BlearyEye
Asked:
BlearyEye
  • 4
  • 4
1 Solution
 
Todd GerbertIT ConsultantCommented:
No bytes available on IP socket does not mean a zero lenght message was received, it means no message was received.
A zero-length message, as defined by your  serial device, is probably an empty string followed by a carriage return/linefeed pair, which would be two bytes.
0
 
BlearyEyeAuthor Commented:
You're right that it's not a keep-alive message; Wireshark flags those, and I can see the keep-alive and the automatic ack going back and forth.

From the C# point of view, the length of messages from the device include cr-lf, so such a message would be length 2, not zero.

For some reason, the keep-alive messages stop after 6 iterations. At that point, a single zero-length [FIN, ACK] message is sent by the device; this is the one that my program picks up. After that, things are quiescent. However, my C# program goes into an infinite loop, apparently getting the same zero-length message again and again.

I'd like to understand why that loop exists and how to handle it appropriately.
0
 
Todd GerbertIT ConsultantCommented:
For some reason, the keep-alive messages stop after 6 iterations. At that point, a single zero-length [FIN, ACK] message is sent by the device
A FIN and FIN/ACK packet pair, in the TCP world, is a graceful closing of the connection. Perhaps something is timing out, causing the network connection to drop.
However, my C# program goes into an infinite loop, apparently getting the same zero-length message again and again
Are you saying that EndReceive is returning 0?
0
Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

 
BlearyEyeAuthor Commented:
You're right about the fin/ack; drilling down into the device config, I see that it was set to timeout after 100 seconds. I'll reset that to no timeout.

EndReceive: yes, rcvlngth, assigned to the value of remote.EndReceive(iar), is zero. So when a fin/ack arrives, I get a zero-length message, and the code I have, which includes a callback repost, puts me into an infinite loop. If I avoid timeout then I shouldn't get fin/ack; but I'd still like to know the right way to handle it if it does show up.
0
 
Todd GerbertIT ConsultantCommented:
Once the connection is dropped, BeginReceive/EndReceive will continue to return 0 - so you just need to check if the connection is still alive before starting another BeginReceive.
You can try checking the Connected property of the socket, which will return the socket's connected status as of the last send or receive operation, but MSDN says if you want to know the current status of the socket you should send a single zero byte and catch the exception.

static void ReceiveData(IAsyncResult iar) { 
    Encoding enc = Encoding.ASCII; 
    Socket remote = (Socket)iar.AsyncState; 
    int rcvlngth = remote.EndReceive(iar); 
    if (rcvlngth > 0) { 
        string rcvd = enc.GetString(data, 0, rcvlngth); 
        Console.WriteLine(rcvlngth.ToString() + ": " + rcvd); 
        remote.BeginReceive(data, 0, data.Length, SocketFlags.None, new AsyncCallback(ReceiveData), remote); 
    } 
    if (rcvlngth <= 0) { 
        Console.WriteLine("hit zero length message"); 
        // *** reset callback 
        if (IsConnected(remote))
          remote.BeginReceive(data, 0, data.Length, SocketFlags.None, new AsyncCallback(ReceiveData), remote); 
    } 
}
static bool IsConnected(Socket sock)
{
  bool connected = true;
  try
  {
    sock.Send(new byte[] { 0 });
  }
  catch // This needs refinement, not all exceptions mean socket is disconnected
  {
    connected = false;
  }
  return connected;
}

Open in new window

0
 
BlearyEyeAuthor Commented:
Thot I'd posted a follow-up comment but saw that it never made it to the site ...

That worked, thx. What's odd is that if I check the Connected property just before sending the sock.Send(new byte[] { 0 }), it says connected (even tho it isn't) but just after, in the catch, it says it's not connected.

Thx for the pointer. Will assign points ...
0
 
Todd GerbertIT ConsultantCommented:
What's odd is that if I check the Connected property just before sending the sock.Send(new byte[] { 0 }), it says connected (even tho it isn't) but just after, in the catch, it says it's not connected.
Yup, that's because the "Connected" property of the socket only reflects it's state as of the most recent send operation - which is why MSDN suggests attempting to send a zero byte.
0
 
BlearyEyeAuthor Commented:
ok, thx.

i just posted another question wrt TCP keepalive ... take a look ... http://www.experts-exchange.com/Programming/Languages/.NET/Q_25960893.html
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

  • 4
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now