8

My C# .net application currently does the following (among other things):

  1. Creates a thread which opens a socket on a specific port and waits for an instruction.
  2. Message comes in, socket thread reads the message and raises an event.
  3. An event handler calls the necessary functions to parse the message and performs the necessary action, for instance, launching an application.
  4. The specified external "application" launches, asynchronously.

When my application restarts, but the external application does not close, the socket doesn't seem to ever close. Then when I try to start up communication on that port again I get an error. However, as soon as I close the external application I am able to open a socket on that port.

It seems like my program is not closing down properly. It should be killing the socket when it exits, however when the external process is running that socket never closes.

Any ideas?

JSideris
  • 5,101
  • 3
  • 32
  • 50
  • Are you disposing the socket? – M.Babcock Apr 19 '12 at 19:12
  • How are you running the external process? Please post some code. – zmbq Apr 19 '12 at 19:15
  • @M.Babcock Yes I am closing the socket and I've verified that the code is being executed when the UI is closed. I'm using a TcpClient and a TcpListener. The client is being "closed" and the listener is being "stopped". However this does not seem to free up the port. – JSideris Apr 19 '12 at 19:27
  • @zmbq very simple - I'm creating a new "Process" object, setting the path, starting it, and disposing of the output. I don't wait for it to close, I just create it and go. – JSideris Apr 19 '12 at 19:29
  • @nos I can try waiting longer. I've verified that the socket does close instantly as soon as my external process (firefox for the purpose of testing) is closed, however as long as firefox is open (I've waited for up to 10 minutes so far) the socket doesn't become available. It may just be an issue where the OS thinks that the external app is part of my process and doesn't want to free up the port. I'll try re-opening it right after closing it to see what happens... – JSideris Apr 19 '12 at 19:32
  • Actually, I'd not be surprised if Process.Start(..) makes the child inherit the open handles. atleast if UseShellExecute is false. Are you using Process.Start() or something else ? – nos Apr 19 '12 at 19:33

5 Answers5

17

This is just a stab because I have seen how you're starting the external process. If you're creating a Process object, my guess is you're not setting:

ProcessStartInfo.UseShellExecute = true;

If UseShellExecute is set to false, the child process will inherit open socket handles from the parent process. This will keep your socket open even if the parent application is closed.

Josh
  • 2,955
  • 1
  • 19
  • 28
  • Right on the money. UseShellExecute was being set to false so that I could redirect/dispose of the input streams. After getting rid of the redirection and setting UseShellExecute to true the ports get freed up. Thanks! – JSideris Apr 19 '12 at 21:19
  • Glad I could help. We just ran into this issue about a month ago. We were receiving socket error after socket error even when the objects were disposing properly. Luckily one of the guys here found it buried somewhere on MSDN. – Josh Apr 20 '12 at 13:34
  • same as [http://stackoverflow.com/a/24677139/4123833](http://stackoverflow.com/a/24677139/4123833) , contains another two solution/options in that. – aspark Apr 06 '16 at 01:55
1

From what I found here my suspicion might be confirmed that this is a case of the new process inheriting handles from the parent, thus causing your issue.

It looks like you can just copy/paste the code from that link to do a direct call to the Windows CreateProcess API with the flag set so as to not inherit handles.

Another separate idea is to write an intermediate launcher program that takes the command line information and then launches and then quits. This extra indirection might get you where you need to be with very little effort.

Aaron Anodide
  • 16,906
  • 15
  • 62
  • 121
  • It seems that `cmd` would be a good fit for such an _intermediate launcher_ with extremely little effort. – M.Babcock Apr 19 '12 at 19:53
0

You might be able to solve this with the using keyword

using (Socket socket = new Socket()) {
//The code
}

Does the other application use the socket at all?

Anders
  • 567
  • 1
  • 7
  • 23
  • The other application does not use the socket. I'm testing it with a random application on my system ... for instance firefox. – JSideris Apr 19 '12 at 19:19
  • Just to make sure - if you do not open an external application, does your problem then release the socket? – Anders Apr 19 '12 at 19:24
  • Yes the socket is released when the external app isn't launched. – JSideris Apr 19 '12 at 21:08
0

The first thing is to take a look on the socket state when the application is closed. The socket could be in the TIME_WAIT state that means that it will wait for some time in order to make sure that no other messages will be received. You can read about that here: http://www.isi.edu/touch/pubs/infocomm99/infocomm99-web/ Now the TIME_WAIT state will be generated on the socket according to which of them initiated the connection termination procedure. So if for some reason your socket perform the close action in the server site then in the server site ( in the server's port ) the socket will change the state to the TIME_WAIT, so if you restart your server application during the socket is in TIME_WAIT a new socket will fail to bind to the listening port, I thing that this is the problem you met.

AlexTheo
  • 4,004
  • 1
  • 21
  • 35
0

Another solution got from the awnser.

If you must set ProcessStartInfo.UseShellExecute to false to use the redirect/dispose of the input stream, a better solution is to set socket handle option to prevent the inheritance by the child process.

It can be done via a P/Invoke SetHandleInformation on the socket handle whick can be obtained from TcpListener.Server.Handle or anywhere:

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetHandleInformation(IntPtr hObject, uint dwMask, uint dwFlags);
private const uint HANDLE_FLAG_INHERIT = 1;

private static void MakeNotInheritable(TcpListener tcpListener)
{
    var handle = tcpListener.Server.Handle;
    SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
}