Quantcast
Channel: listener – Learn Powershell | Achieve More
Viewing all articles
Browse latest Browse all 4

Checking For Disconnected Connections with TCPListener Using PowerShell

$
0
0

Working on my PoshChat project, one of the things that I was dealing with was handling connections that was disconnected through different means other than just the client disconnecting on its own such as a client being rebooted or the network just dropping the connection.

After some research and testing, I found an approach that seems to handle dropped connections and alert the Listener when the client has disconnected the connection. The approach is done by using a Poll() method from the Client object (more on this in my example). By doing this, we can test to see if the remote end connection is still available and if it isn’t available, we can process that as a closed connection and dispose of the connection objects.

Set up the Listener

Let’s get started with this. First thing is that I am going to create the the listener object and start it up so I can begin accepting TCP connections.

$Listener = [System.Net.Sockets.TcpListener]15600
$Listener.Start()

SNAGHTML2571d6ca

Now that we have our listener up and going, we can start monitoring for incoming connections using an approach I talked about a while back.

If ($Listener.Pending()) {
    ...
}

Client connection

While we are waiting for the connection, we can now initiate that connection from a different console.

$Server = 'Boe-PC'

#Connect to server
$Endpoint = new-object System.Net.IPEndpoint ([ipaddress]::any,$SourcePort)
$Client = [Net.Sockets.TCPClient]$endpoint
$Client.Connect($Server,15600)

And now we will have a pending connection on the server. This means we get to accept the client connection.

$ServerClient = $Listener.AcceptTcpClient()

Write-Verbose ("[$(Get-Date)] New Connection from {0} <{1}>!" -f $ServerClient.Client.RemoteEndPoint.Address,
$ServerClient.Client.RemoteEndPoint.Port) –Verbose

image

We can verify that the connection is established.

SNAGHTML257b614c

Now note the Connected property here on the server side client. Currently it shows as being connected when I view its properties.

image

Now let’s view it again.

SNAGHTML257c506e

That is weird. What in the world does this mean? The connection still shows as being good when I view the TCP connections, but I am seeing the client showing it as no longer connected. Well, this is because this value updates based on the last time an I/O operation has occurred. So we had the initial data transfer when I viewed it initially, but now that nothing has occurred prior to this viewing, it simply shows as being false.

This means that we should not use just this approach as a reliable way of testing a connection between to endpoints. Enter the Poll method that I mentioned earlier.

image

This takes two parameters: the number in milliseconds that it will take to poll and the type of SelectMode to test for. I am using SelectRead because I want to know if the connection has been reset, terminated or closed. I am also going to be combining this with checking the Available property as well.

A quick test will show that the connection is still available even though the Connected property is showing False.

$ServerClient.Client.Poll(1,[System.Net.Sockets.SelectMode]::SelectRead)

image

Currently shows False, which means that we do not have any connection issues, but also keep in mind that this also means that we do not have any data available, which is why we also need to throw in the DataAvailable check as well.

While (-NOT ($ServerClient.Client.Poll(1,[System.Net.Sockets.SelectMode]::SelectRead) -AND
$ServerClient.Client.Available -eq 0)) {
    Start-Sleep -Milliseconds 100
}

Let’s assume that we have a network issue (in my case I am closing the PowerShell console). Once the poll runs, it will see that the return from the Poll is True and since there is no data available, it sees this as a closed connection and processes it accordingly.

Write-Verbose "[$(Get-Date)] Connection has closed remotely" -Verbose
#Shutdown the connection
Write-Verbose "[$(Get-Date)] Closing socket" -Verbose
$ServerClient.Client.Shutdown([System.Net.Sockets.SocketShutdown]::Both)
$ServerClient.Client.Close()

image

And now we are back to just the listener showing up in our TCP connections.

image

In my testing, I have found this to be a good approach to tracking multiple connections to a single listener and in handling their sudden disconnects. In my case I am using runspaces to handle the listener, the subsequent connections, performing Poll checks as well as data send and receives. This helps in the case where I have some data that has been sent to the server prior to a disconnect happening in that it will be processed in a different thread and resets the DataAvailable back to 0 which will cause the Poll thread to see that the client has disconnected on its next check. Otherwise if you are not handling the incoming data receives, you will have a harder time of determining that a disconnection has occurred.

While I do not doubt that this has a small audience who may use this, it will hopefully help out those who are in a similar situation as me when it came to handling these disconnects gracefully.


Filed under: powershell Tagged: .net, listener, Powershell, tcp

Viewing all articles
Browse latest Browse all 4

Latest Images

Trending Articles





Latest Images