-1

I’m currently working on a project in which I need to receive data from devices over GPRS. These devices send their data to a TCP server listening on a port on my server. I first had the problem with connecting multiple devices and after some research I learned that I should implement an Asynchronous approach. I now have 1 TCP socket listening for incoming connections and as soon as a request comes in this is put in a new socket connection, freeing the listening socket for other connection attempts.

My challenge: I am testing with 2 devices, these connect successfully and can send their data. When I turn off a device (remove battery and SIM) I am not able to detect that this device is no longer connected and close the socket. When running a netstat on the port of the listener I still see 2 devices with connection ‘ESTABLISHED’.

I have tried various examples but the various socket polling options all return ‘true’. The only option that works now is trying to send some data to the socket which will fail and gets catched and then return a false value. Setting the ReceiveTimeout property on the socket also does not help. Thing I tried:

socket.Poll(1000, SelectMode.SelectWrite); //returns true
socket.Poll(1000, SelectMode.SelectRead); //returns true
socket.Available = 0 (available);
  • It is a duplicate question but the solution in your post is not working for me since I tried that code and posted it in my question. – Niels de Schrijver Nov 08 '17 at 11:11
  • Aside from a "tidiness" argument, is not detecting the loss of the connection causing you actual issues? – Damien_The_Unbeliever Nov 08 '17 at 11:13
  • 3
    You cannot detect loss of connection this way because it's not actually lost, as you see yourself in netstat. Closing TCP connection requires specific handshake (exchange of data between connected sides) and when you remove battery from your device - this handshake does not happen. So one side is "dead" but connection is not closed. If you only read data without sending - you can wait for data forever in this case. You can read this article with discussion of possible ways to resolve your issue: https://blog.stephencleary.com/2009/05/detection-of-half-open-dropped.html – Evk Nov 08 '17 at 11:19
  • Hi Evk, thank you for the link! I also found this article but as the article states the options also need adjustment in me 'sender side' this is not an option for us. I can only create the receiving end. – Niels de Schrijver Nov 08 '17 at 11:31
  • @NielsdeSchrijver - the timer solution is, as indicated, one that can be implemented without requiring changes at the other end. – Damien_The_Unbeliever Nov 08 '17 at 11:34
  • Well you don't have much options here. Seems the only way left is to use timeouts. When there is no data available for X minutes - assume connection is dead and drop it. The other party will reconnect (I assume) if it was not really dead. – Evk Nov 08 '17 at 11:46
  • Yes I guess so, I really don't like that option since I might miss messages in the process. The upside is that my devices always first send a serial as the first message so I will put the serial with the corresponding socket in a Dictionary and check for duplicates. Also after X time like you suggested disconnect the socket. – Niels de Schrijver Nov 08 '17 at 12:13
  • 1
    Your question has been asked over and over in various forms, and there are plenty of posts you can read. See marked duplicate. Bottom line: TCP is _designed_ to not drop a connection until it hits a hard failure. I.e. the remaining endpoint tries to send while the connection isn't present. You can add mechanisms to send periodically, but this just adds overhead and _reduces_ reliability, since now transient interruptions in the connection will cause an error when they otherwise wouldn't have. – Peter Duniho Nov 09 '17 at 03:43

1 Answers1

0

Using code like

 'if(socket.Connected) { socket.Write(...) }

creates a race condition. You're better off just calling socket.Write and handling the exceptions and/or disconnections.

Socket layer shall managed using exceptions. The IOException thrown has the inner exception set to a SocketException, which contains all information required to detect timeouts or closed sockets remotely

Muhammad Ali
  • 129
  • 7
  • Hi Muhammad, thank you for trying to help me. How is your awnser different from my comment "The only option that works now is trying to send some data to the socket which will fail and gets catched" – Niels de Schrijver Nov 08 '17 at 11:28