I am working with some legacy TCP server code that works with sockets directly as it was written in .NET 2.0 and earlier. The server has a feature to 'stop' and 'start' accepting client connections.
To troubleshoot the issue I run the server in the console mode as admin user. On top of that I have eliminated the socket accept thread from the equation and all the code does is something like:
tcpListener = new TcpListener(IPAddress.Any, this.Port);
tcpListener.Start();
and
tcpListener.Stop();
This called from different methods. I have debugged the code and I am pretty sure the code executes only once. However, the issue is that call to Stop
does not actually releases the socket address and subsequent call to Start
therefore fails with the error "Only one usage of each socket address (protocol/network address/port) is normally permitted". I can also confirm from the ProcessExplorer that the server is still listening on the server port.
When I write a small console app that uses the same code snippets everything works fine. I have even tried tracing the .NET network and socket libraries, but there is no error or anything to indicate problems there.
It is not clear to me why call to Stop
does not release the socket address?
Update:
After more investigation it turns out that there is some strange effect of child process launch to the TcpListener
. I have made a 'bare bone' sample code that illustrates the issue:
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Threading;
namespace TcpListenerStartStop
{
class MyTcpListener
{
public static void Main(string[] args)
{
Int32 port = 13000;
if (args.Length > 0) // indicates child process
{
Thread.Sleep(4000); // as a child do nothing and wait for a few seconds
}
else // parent will play with the TcpListener
{
//LaunchChildProcess(); // launch child here and listener restart is fine?!?
var tcpListener = new TcpListener(IPAddress.Any, port);
tcpListener.Start();
Console.WriteLine("Starting test in 2 seconds...");
Thread.Sleep(2000);
LaunchChildProcess(); // launch child here and listener restart is not fine?!?
tcpListener.Stop();
Console.WriteLine("Stopped.");
Thread.Sleep(1000);
tcpListener.Start();
Console.WriteLine("Started");
}
Console.WriteLine("All is good, no exceptions :)");
}
private static void LaunchChildProcess()
{
Process process = new Process();
var processStartInfo = new ProcessStartInfo
{
CreateNoWindow = true,
FileName = Assembly.GetExecutingAssembly().Location,
UseShellExecute = false, // comment out this line out listener restart is fine?!?
Arguments = "child"
};
process.StartInfo = processStartInfo;
process.Start();
}
}
}
As you can see from the code if I launch the child process before creating a listener everything is fine, if I do it after listener restart fails. This has something to do with the UseShellExecute = false
option for the child process.
Not sure if this is .NET bug or some special behavior I was not aware of?
Stop()
does release the socket but it immedatly starts a new one. EDIT: nevermind, it is a unbound socket. – Asphyxiant