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

LVL 1
BlearyEyeAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

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
OWASP: Avoiding Hacker Tricks

Learn to build secure applications from the mindset of the hacker and avoid being exploited.

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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
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
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.