2

Been searching for this for over an hour now, and I have not found in documentation nor in examples on the web how to enable the SO_REUSEADDR option when working with the HttpListener class.

My specific use case is within a Powershell script, but even if there is an answer in C#, that would be fine. This is about as cut-and-dry as it gets:

$Listener = New-Object System.Net.HttpListener
$Listener.Prefixes.Add('http://+:9999/')
Try
{
    $Listener.Start()
    # While loop here to handle requests; omitted for brevity
}
Catch
{
    # omitted here for brevity
}

There are times where I Ctrl-C to break out of the script while testing, and leaving the loop this way does not allow $Listener.Stop() to be called and the socket properly closed. (Yes, I know - don't do this if it breaks things)

Normally, when I need a listening socket, I make use of SO_REUSEADDR to handle those times where things don't clean up properly to allow me to restart my listener without having to wait 30 minutes for the port to be available again. Is there a way to do this with HttpListener and I'm just missing it?

Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
Will
  • 3,500
  • 4
  • 30
  • 38

1 Answers1

2

No, you can't use SO_REUSEADDR with HttpListener.

The reason is that the HttpListener doesn't actually manage the underlying socket - it simply registers application-level prefixes with the HTTP.sys driver, who in turn manages the underlying connection.

To use SO_REUSEADDR, you could create a TcpListener and set the socket option on the underlying socket (accessible through the Server property) with SetSocketOption():

$TcpListener = New-Object System.Net.Sockets.TcpListener 9999
$TcpListener.Server.SetSocketOption("Socket", "ReuseAddress", 1)
$TcpListener.Start()

But now you have to implement all the convenient things that HttpListener provides on you own (header parsing, content validation etc.).


That being said, this may solve the practical issue you face:

try{
    $Listener.Start()
}
catch{
}
finally{
    $Listener.Stop()
    $Listener.Dispose()
}

(don't paste this into you prompt/ISE, you need to save this to a script, or enclose in a script block for finally to be evaluated properly on interruption)

Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • Ok, so I guess it's just a matter of trade-off between using the canned HttpListener or doing it all by hand with TcpListener. I'm a bit surprised that the HttpListener implementation doesn't take something like this into consideration. Added the Try/Catch/Finally since that seems to be the easiest/quickest solution. Thanks – Will Feb 10 '16 at 19:37
  • I'm not sure what you mean by "taking something like this into account" - the `HttpListener` is not the one binding to the socket, there's not much it can do about it. `HttpListener` implements `IDisposable` to handle freeing the http prefix registrations, but since there's no `using()` construct in PowerShell, we'll have to rely on `try/catch/finally` – Mathias R. Jessen Feb 10 '16 at 20:09