如果启动的进程处于打开状态,则在应用程序退出后,套接字不会关闭

本文关键字:退出 套接字 应用程序 进程 启动 于打开 如果 状态 | 更新日期: 2023-09-27 18:31:36

我的 C# .net 应用程序当前执行以下操作(除其他事项外):

  1. 创建一个线程,该线程在特定端口上打开套接字并等待指令。
  2. 消息
  3. 传入,套接字线程读取消息并引发事件。
  4. 事件处理程序调用必要的函数来分析消息并执行必要的操作,例如,启动应用程序。
  5. 指定的外部"应用程序"异步启动。

当我的应用程序重新启动,但外部应用程序没有关闭时,套接字似乎永远不会关闭。然后,当我尝试再次在该端口上启动通信时,出现错误。但是,一旦我关闭外部应用程序,我就可以在该端口上打开一个套接字。

似乎我的程序没有正确关闭。当套接字退出时,它应该杀死套接字,但是当外部进程运行时,该套接字永远不会关闭。

有什么想法吗?

如果启动的进程处于打开状态,则在应用程序退出后,套接字不会关闭

这只是一个刺痛,因为我已经看到了你是如何启动外部进程的。 如果您正在创建一个 Process 对象,我猜您没有设置:

ProcessStartInfo.UseShellExecute = true;

如果 UseShellExecute 设置为 false,则子进程将从父进程继承打开的套接字句柄。 即使父应用程序已关闭,这也将使套接字保持打开状态。

从我在这里发现的内容来看,我的怀疑可能会得到证实,这是新进程从父进程继承句柄的情况,从而导致您的问题。

看起来你可以从该链接复制/粘贴代码,直接调用Windows CreateProcess API,并设置标志,以便不继承句柄。

另一个单独的想法是编写一个中间启动程序,该程序获取命令行信息,然后启动然后退出。 这种额外的间接寻址可能会让您毫不费力地到达您需要的地方。

您可以使用 using 关键字解决此问题

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

其他应用程序是否使用该套接字?

第一件事是查看应用程序关闭时的套接字状态。套接字可能处于TIME_WAIT状态,这意味着它将等待一段时间以确保不会收到其他消息。你可以在这里阅读:http://www.isi.edu/touch/pubs/infocomm99/infocomm99-web/现在,将根据哪个套接字启动连接终止过程,在套接字上生成TIME_WAIT状态。因此,如果由于某种原因您的套接字在服务器站点中执行关闭操作,那么在服务器站点(在服务器的端口中)中,套接字会将状态更改为TIME_WAIT,因此,如果您在套接字处于TIME_WAIT期间重新启动服务器应用程序,则新套接字将无法绑定到侦听端口, 我想这就是你遇到的问题。

另一个解决方案来自遮阳篷。

如果必须将ProcessStartInfo.UseShellExecute设置为 false 才能使用输入流的重定向/处置,更好的解决方案是设置套接字句柄选项以防止子进程继承。

它可以通过套筒手柄上的P/Invoke SetHandleInformation完成,可以从TcpListener.Server.Handle或任何地方获得:

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