Link to home
Start Free TrialLog in
Avatar of mediasoftware
mediasoftware

asked on

VB.NET 2008 TcpClient socket keep-alive

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.
Avatar of Ron Malmstead
Ron Malmstead
Flag of United States of America image

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
https://www.experts-exchange.com/questions/21561597/TCP-IP-Sockets.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

Avatar of mediasoftware
mediasoftware

ASKER

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.
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
           
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.
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
ASKER CERTIFIED SOLUTION
Avatar of Ron Malmstead
Ron Malmstead
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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.
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.
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?
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.
Thank you.