Я работаю с некоторым старым кодом TCP-сервера, который работает с сокетами напрямую, как это было написано в .NET 2.0 и ранее. Сервер имеет функцию «остановить» и «начать» прием клиентских подключений.Метод .NET TcpListener Stop не останавливает прослушиватель, когда есть дочерний процесс
Чтобы устранить проблему, я запускаю сервер в консольном режиме как пользователь admin. Кроме того, я устранил сокет принимает нить из уравнения и весь код делает это что-то вроде:
tcpListener = new TcpListener(IPAddress.Any, this.Port);
tcpListener.Start();
и
tcpListener.Stop();
Это вызывается из различных методов. Я отлаживал код, и я уверен, что код выполняется только один раз. Однако проблема заключается в том, что вызов Stop
фактически не освобождает адрес сокета, и последующий вызов Start
, следовательно, с ошибкой «Обычно разрешено только одно использование каждого адреса сокета (протокола/сетевого адреса/порта)». Я также могу подтвердить из ProcessExplorer, что сервер все еще прослушивает порт сервера.
Когда я пишу небольшое консольное приложение, которое использует одни и те же фрагменты кода, все работает нормально. Я даже попытался отслеживать библиотеки .NET и сокетов, но нет никаких ошибок или каких-либо проблем, чтобы указать на проблемы.
Непонятно мне, почему звонок Stop
не освобождает адрес сокета?
Update: После еще расследования выясняется, что есть какой-то странный эффект запуска дочернего процесса в 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 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();
}
}
}
Как видно из кода, если я запускаю дочерний процесс перед созданием слушателя все нормально, если я сделаю это после перезагрузки слушателя выходит из строя. Это как-то связано с опцией UseShellExecute = false
для дочернего процесса.
Не уверен, что это ошибка .NET или какое-то особое поведение, о котором я не знал?
[Из документации] (https://msdn.microsoft.com/en-us/library/system. net.sockets.tcplistener.stop (v = vs.110) .aspx # Anchor_2): «* Примечания к вызывающим: метод Stop также закрывает базовый Socket и создает новый Socket для TcpListener. Если вы установите какие-либо свойства на лежащий в основе Socket до вызова метода Stop, эти свойства не переносятся на новый Socket.* ", из этого кажется, что вызов' Stop() 'действительно освобождает сокет, но он сразу начинает новый. EDIT: неважно, это несвязанный сокет. –