Checking For Disconnected Connections with TCPListener Using PowerShell

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.

Posted in powershell | Tagged , , , | Leave a comment

Coming Soon: PowerShell Blogging Week

Beginning March 30th and running until April 4th, a handful of PowerShell MVPs and enthusiasts will be taking part in PowerShell Blogging Week. This is the first time that we are attempting this and what we have in store if a weeks worth of topics about various pieces of PowerShell.

What are we covering? Well, that will remain a secret until each article is published. Just be sure to watch Twitter with the hashtag #PSBlogWeek.

What I can do is show you who is writing during the week so you can better watch for those articles!

Name

Twitter

Blog

Adam Bertram

@adbertram

http://www.adamtheautomator.com

Mike F. Robbins

@mikefrobbins

http://mikefrobbins.com/

Boe Prox

@proxb

http://learn-powershell.net/

Francois-Xavier Cat

@lazywinadm

http://www.lazywinadmin.com/

June Blender

@juneb_get_help

http://www.sapien.com/blog/

Jeffrey Hicks

@JeffHicks

http://jdhitsolutions.com/

Posted in News, powershell | Tagged , , | Leave a comment

Slides and Example Code From Nebraska.Code() Conference Session Available

I had the great opportunity to speak at Nebraska.Code() over the weekend in which I talked about Trend Reporting using PowerShell and SQL. This was a great opportunity and my 1st conference speaking gig that I have done. I appreciate everyone who attended and provided some excellent feedback during the session.

My slide deck and code examples are available below on Nebraska.Code’s github repo to download. Feel free to check them out and let me know what you think!

https://github.com/nebraskacode/2015-Slides-and-Demos/tree/master/Trend_Reporting_Using%20SQL_and_PowerShell

Posted in powershell | Tagged , , , | Leave a comment

MCPMag Articles on Exploring PowerShell

My series of articles for this month on MCPMag.com talk about exploring PowerShell using a few of the available cmdlets. I’ll update the links as each new article goes live below.

Exploring PowerShell, Part 1: Using Get-Command

Exploring PowerShell, Part 2: Learn the Commands Using Get-Help

Exploring PowerShell, Part 3: Using Get-Member To Dig into .NET Objects

Posted in powershell | Tagged , , , | Leave a comment

Checking for a TCP Listener Connection

I’ve been spending some time re-writing my PoshChat project to replace various things that I feel could have been written better as well as trying to knock out some of the issues that I had in the beginning but just never got around to fixing. One of those items was how I was using the System.Net.Sockets.TcpListener and setting it up to listen for new connections and then handling those connections (usually in another runspace) so I still have the room to handle other new connections.

The ‘Old” Way

The big issue here is that I was using the AcceptTCPClient() method, which presents a blocking call on the console. This means that I cannot do anything else at all, which really wasn’t an issue for me because I had all of this operating in its own runspace. The code snippet below shows the setting up of the runspace that will be handling the listener as well as when connections happen.

$SharedData = [HashTable]::Synchronized(@{})
$Listener = [HashTable]::Synchronized(@{})

#Initial runspace creation to set up server listener 
$NewRunspace = [RunSpaceFactory]::CreateRunspace()
$NewRunspace.Open()
$NewRunspace.SessionStateProxy.setVariable(&amp;quot;sharedData&amp;quot;, $sharedData)
$NewRunspace.SessionStateProxy.setVariable(&amp;quot;Listener&amp;quot;, $Listener)
$NewPowerShell = [PowerShell]::Create()
$NewPowerShell.Runspace = $NewRunspace
$sb = {
     $Listener['listener'] = [System.Net.Sockets.TcpListener]15600
     $Listener['listener'].Start()
    while($true) {
    [byte[]]$byte = New-Object byte[] 1024
    $client = $Listener['listener'].AcceptTcpClient()
    If ($client -ne $Null) {
        $stream = $client.GetStream()
        # ... #
    } Else {
        #Connection to server closed
        Break
    }
    }#End While
}
$Handle = $NewPowerShell.AddScript($sb).BeginInvoke()

You can see where I begin using AcceptTCPClient() which presents the blocking call. What happens is that at this point I have no way to break out of this call. Even if I were to change the $True to $False in my While() {} statement, it wouldn’t matter because of the blocking call. Obviously, this presents an issue if I wanted to halt my chat server which would mean completely halting the PowerShell process to effectively stop the listener.

The “New” Way using Pending()

The solution that I have found involves using the Pending() method of the listener object. By still using a loop and instead calling the Pending() method which will return $True for a connection that is attempting to be made to the listener and $False if no connections are being attempted, we can keep from blocking the runspace and allow us to inject a variable update to halt the loop if we wanted to shut down the server. Let’s give it a shot and see what happens.

First we need to start out listener:

#Create the listener and kick it off
$Listener = [System.Net.Sockets.TcpListener]15600 
$Listener.Start()

image

Ok, now if we check for pending connections, we will get back a False, meaning that there are no connections currently being attempted.

$Listener.Pending()

image

Since that is the case, I would simply start a sleep cycle for a second and check again. But now let’s assume that a connection was attempted (using the code below) and we can check again to see what happens.

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

Now we can check for pending connection attempts.

image

Looks like we have a connection being made, so we had better act on it by calling the AcceptTCPClient() method. We also can open up a stream during this process as well.

$Client = $Listener.AcceptTcpClient() 
$ClientConnections = $Client  
$ClientStream = $Client.GetStream()         
Write-Verbose (&amp;quot;[$(Get-Date)] New Connection from {0} &amp;lt;{1}&amp;gt;!&amp;quot; -f 
$Client.Client.RemoteEndPoint.Address, $Client.Client.RemoteEndPoint.Port) –Verbos

e

image

Perfect! Now we can begin doing whatever should be done with this new connection. In this case, I am not going to do anything with it, but in PoshChat, this would get handed off to another runspace to handle the client connection and stream for messaging and the listener would be back watching for new connections.

By watching for Pending() connections, we avoid being blocked by the AcceptTCPClient() method and can then easily close our listener up without completely trashing our current PowerShell console.

Hopefully this approach helps you out if you happen to be working with client connections to a listener and provides a way to more easily handle tracking those new connections to the listener without completely taking away your ability to shut down the listener.

Posted in powershell | Tagged , , , | 1 Comment