简体   繁体   中英

Socket doesn't close after application exits if a launched process is open

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?

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.

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.

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?

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.

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM