We help IT Professionals succeed at work.

VB.NET 2008 TcpClient socket keep-alive

mediasoftware
mediasoftware used Ask the Experts™
on
Hello,

I am building a Client/Server application in VB.NET 2008. I am looking for the best way to detect when a connection is dropped (not when the server program explicitly disconnects the client, but when the line is ‘cut’).

I do not want to make a custom protocol for sending and receiving packets every few seconds to detect if the connection is still available.

Also, I am aware about the NetworkChange.NetworkAddressChanged event, from the following article on MSDN:
http://msdn.microsoft.com/en-us/library/system.net.networkinformation.networkchange.networkaddresschanged.aspx

The NetworkChange.NetworkAddressChanged event detects only when the client unplugs his own network cable. It is not useful if the line is dropped somewhere else between the client and the server.

I know the sockets have a KeepAlive option:
myTcpClient.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, 1)

but is very little documentation.

I need an implementation of this in VB.NET 2008, or an solution of any kind for raising an event when the connection is dropped somewhere else between the client and the server.

Thank you.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Ron MalmsteadInformation Services Manager

Commented:
If you can post some code, that would be helpful.

.... I assume somewhere in your Recieve() sub, you are using a "While", to process data recieved on the socket.

Do a TRY on the While....(while recieving)..., and catch ex as exception.  If the client disconnects from the socket, or the socket is dropped, you can raise the event in the catch.

I believe...could be wrong on this however...that the timeout is for the socket itself, when no data is recieved for a period of time.

...example below.
In this example...slightly modified code from EEmember: dheenu27
Each socket connection is passed off to Recieve() on a seperate thread.
Try ,WHILE... recieving...  loops as data arrives and fills the byte array....
If the data stops or the socket is broken by the client... it goes to Catch
http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_21561597.html?sfQueryTermInfo=1+connect+socket+vb.net
Imports System.Net.Sockets
Imports System.Net
Imports System.Threading

Module Module1
    Public Structure ClientInfo
        Public Socket As Net.Sockets.Socket
        Public Thread As Threading.Thread
    End Structure



    Private TempTable As New Hashtable
    Private connectId As Long = 0

    Sub Main()

        Dim tcpLsn As New TcpListener(IPAddress.Any, 8888)
        Dim CData As ClientInfo

        tcpLsn.Start()
        While True
            CData.Socket = tcpLsn.AcceptSocket()
            
            Interlocked.Increment(connectId)
            CData.Thread = New Thread(AddressOf ReadSocket)
            TempTable.Add(connectId, CData)
            CData.Thread.Start()
          
        End While
    End Sub

    Public Sub ReadSocket()
        Dim clientId As Long = connectId
        Dim receive() As [Byte]
        Dim cd As ClientInfo = CType(TempTable(clientId), ClientInfo)
        Dim s As Socket = cd.Socket
        Dim ret As Integer = 0
      

        While True
            If Not s Is Nothing Then
                If s.Connected Then
                    receive = New [Byte](1024) {}

                    Try
                        ret = s.Receive(receive, receive.Length, SocketFlags.None)
                        Dim str As String = System.Text.Encoding.ASCII.GetString(receive).Replace(vbNullChar, "")
                        Console.Write(Trim(str))

                        Dim pMessage As New ProcessMessage
                        pMessage.Message = (Trim(str))

                        Dim t As Thread
                        t = New Thread(AddressOf pMessage.go)
                        t.Start()


                        'Reply to client recieved!
                        Dim sendBuff() As [Byte]
                        Dim buffChar As Char() = ("RECIEVED !").ToCharArray

                        sendBuff = System.Text.Encoding.ASCII.GetBytes(buffChar)
                        s.Send(sendBuff, SocketFlags.None)

                    Catch ex As Exception
'Client connection interruptions, or client disconnects.
                        Exit While
                    End Try



                End If
            End If
        End While
        s.Shutdown(SocketShutdown.Both)
    End Sub

    Public Class ProcessMessage

        Public Message As String

        Public Sub go()
'Do something with the message
            MsgBox(Message)

        End Sub

    End Class

End Module

Open in new window

Author

Commented:
Hi,

Thank you for your solution. I'm sorry I did not provide how my code currently works.

Client:
Uses a TcpClient and starts an asynchonus BeginRead, with a DoRead callback that executes when data is received.

Multithreaded Server:
Has a base class for a client, that is instanced for each new connection. This class also uses async BeginRead to receive data.

So, everything is asynchronus, and I do not want to use synchronus 'Receive' calls.

I have to trouble only when the network connection is dropped, not when the connection is explicitly closed either by the client or the server, because in this case I get an exception and I know the connection has closed.

Thank you in advance.
Ron MalmsteadInformation Services Manager

Commented:
I don't know why you would need to re-invent the wheel.
You should be able to get the TcpClient state at any time.

Dim tcpcli As TcpClient
....
Dim isconnected as boolean = tcpcli.Connected
           

Author

Commented:
Hi,

It's not about re-inventing the wheel. The .Connected property only works to detect if the connection was explicitly and properly terminated by either client or server.

If you try this by plugging out your network cable you will see that the .Connected property still reads true.

What I need to detect is when the connection is 'cut' un-properly, like when the connection between the client and server drops somewhere in between.

Thank you.
Ron MalmsteadInformation Services Manager

Commented:
Ok, so maybe i'm not understanding this right....
You want to verify the host is available before you even connect, or send data ?
In that case you would be correct, because ....

Socket.Connected
Summary:
Gets a value that indicates whether a System.Net.Sockets.Socket is connected to a remote host as of the last Overload:System.Net.Sockets.Socket.Send or Overload:System.Net.Sockets.Socket.Receive operation.

Return Values:
true if the System.Net.Sockets.Socket was connected to a remote resource as of the most recent operation; otherwise, false.

.... so it would still read True, if the last operation worked....

Ok...
So wouldn't a simple ping test verify it ?

Private Function PingVer(byval servername as string)
 Dim Connectable as boolean = true
 Dim verconnection As New System.Net.NetworkInformation.Ping
            Try
                verconnection.Send(servername, 100)
            Catch ex As Exception
Connectable = false
'                MsgBox(ex.Message)
            End Try
Return Connectable
End function
Information Services Manager
Commented:
Seems you could just use ping on a timer, or seperate thread in a loop...continuously... and if it gets err, then you set a public ver to break it all off.

Author

Commented:
No, I do not want to check before the connection is made.

I know it can be done with a timer and a ping, or by sending and recieving messages every few seconds to check the connection is still online.

But I would like a more "authentic" method, more like an event. Possibly something involving:

myTcpClient.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, 1)

KeepAlive option seems to be a native built-in function, to accomplish this task. I would like to stick to this idea.

Thank you.

Author

Commented:
I want to thank for all those experts that had the time to take a look over my request.

I finally found a solution on this page:
http://social.msdn.microsoft.com/Forums/en-US/netfxnetcom/thread/d5b6ae25-eac8-4e3d-9782-53059de04628/

Thank you.
Ron MalmsteadInformation Services Manager

Commented:
I found the same thing, after many googles, but I didn't post it because I can't get it to work.
Is it actually working for you?

Author

Commented:
Indeed, after many tests with that code it doesn't seem to work.

I read somewhere it may require registry changes and I do not want to do that.

So, if this will not work, I will probably go with your ping in a timer solution.

What should I do to accept your solution and award the points to you ?

Thank you very much.

Author

Commented:
Thank you.