我正在使用一些传统的 TCP 服务器代码,这些代码直接与套接字一起工作,因为它是在 .NET 2.0 及更早版本中编写的。服务器具有“停止”和“开始”接受客户端连接的功能。
为了解决这个问题,我以管理员用户的身份在控制台模式下运行服务器。最重要的是,我已经从等式中消除了套接字接受线程,所有代码都类似于:
tcpListener = new TcpListener(IPAddress.Any, this.Port);
tcpListener.Start();
Run Code Online (Sandbox Code Playgroud)
和
tcpListener.Stop();
Run Code Online (Sandbox Code Playgroud)
这从不同的方法调用。我已经调试了代码,我很确定代码只执行一次。但是,问题是调用Stop实际上并没有释放套接字地址和随后的调用Start因此失败并显示错误“通常每个套接字地址(协议/网络地址/端口)只允许使用一次”。我还可以从 ProcessExplorer 确认服务器仍在侦听服务器端口。
当我编写一个使用相同代码片段的小型控制台应用程序时,一切正常。我什至尝试跟踪 .NET 网络和套接字库,但没有错误或任何表明存在问题的内容。
我不清楚为什么调用Stop不释放套接字地址?
更新:
经过更多调查发现子进程启动到TcpListener. 我制作了一个“裸骨”示例代码来说明这个问题:
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 …Run Code Online (Sandbox Code Playgroud) 我在使用TCP绑定的自托管应用程序中有一个WCF服务.如果我从应用程序启动一个外部进程"commandLineApp",即使在我的应用程序关闭后仍然继续,我下次在我的应用程序启动WCF服务时会遇到问题.
WCF说地址/端口已经在使用中.如果在重新启动应用程序之前关闭外部应用程序(根本没有使用WCF或任何套接字),WCF服务就可以正常启动.
看起来我的应用程序中的套接字句柄以某种方式由新进程"commandLineApp"继承,并且在该进程退出之前不会被释放.
如何阻止其他进程从我的主应用程序继承句柄(或成为子进程?)?目前我正在使用Process.Start启动其他进程,使用UseShellExecute设置为False,因为我需要设置EnvironmentVarables和RedirectStandardOutput/Error.
我认为如果我设置UseShellExecute = true,则会阻止子进程设置,但是我没有得到我需要的所有功能.
有没有解决这个问题的方法?请参阅下面的示例代码
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "commandLineApp.exe";
psi.Arguments = "/someParameter";
psi.EnvironmentVariables.Add("...", "...");
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.UseShellExecute = false;
Process process = new Process();
process.StartInfo = psi;
process.Start();
// Monitor if process with PID = process.Id is running
// ...
Run Code Online (Sandbox Code Playgroud)
编辑 - 附加信息:执行"netstat -noa"表示该端口与主应用程序的先前PID一起使用状态LISTEN,但不再有该PID的进程.一旦我关闭"commandLineApp",netstat命令就不再列出该端口了.
在主应用程序退出之前,WCF服务将像这样关闭:
try
{
serviceHost.Close(TimeSpan.FromSeconds(4));
}
catch (Exception)
{
serviceHost.Abort();
}
Run Code Online (Sandbox Code Playgroud)