Фоновый поток все еще прослушивает порт TCP после остановки службы - PullRequest
0 голосов
/ 05 июня 2018

Я пишу сервис C # (.NET 4.0), который прослушивает порт TCP.Я запускаю TcpListener в фоновом потоке (используя Task Parallel Library), чтобы служба не реагировала на Windows.Я также использую TPL всякий раз, когда клиент подключается, так как каждый клиент выполняет некоторую работу с базой данных, и я не хочу блокировать других клиентов.

Я устанавливаю и удаляю службу с помощью InstallUtil.exe в Windows Server 2012 R2 Standard.Всякий раз, когда я останавливаю службу и удаляю ее, используя netstat -abo, я вижу, что порт все еще прослушивается процессом [System].У него есть PID, однако я не вижу процесс с этим PID в диспетчере задач или списке задач, и при этом я не могу убить его с помощью taskkill.Он просто говорит, что процесс не найден, но всегда работает, когда запускаю netstat -abo.Если я попытаюсь запустить службу снова, используя тот же порт, я получаю исключение сокета:

Only one usage of each socket address (protocol/network address/port) is normally permitted
Stacktrace:
at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Bind(EndPoint localEP)
at System.Net.Sockets.TcpListener.Start(Int32 backlog)

Я предполагаю, что мои фоновые потоки все еще зависают после остановки службы, но я понятия не имею,как их убить сейчас, и как этого избежать.Вот что, я надеюсь, является соответствующим кодом (удаленная обработка исключений и ведение журнала для удобства чтения):

public partial class MyService : ServiceBase
        {
            private static TCPServer server = null;

            protected override void OnStart(string[] args)
            {
                server = new TCPServer();
            }

            protected override void OnStop()
            {
                if (server != null)
                {
                    server.StopServer();
                }
            }
        }

    class TCPServer
        {
            public static TcpListener listener = null;
            private static Task listenerTask = null;
            private static List<Task> clientTasks = new List<Task>();

            public TCPServer()
            {
                    listenerTask = new Task(() => StartServer());
                    listenerTask.Start();
            }

            public void StopServer()
            {
                foreach(Task task in clientTasks)
                {
                    task.Dispose();
                }

                    listenerTask.Dispose();

                    if (listener != null)
                    {
                        listener.Stop();
                        listener = null;
                    }
            }

            private void StartServer()
            {
                    Int32 port = 51987;
                    IPAddress localAddr = GetLocalIP();

                    listener = new TcpListener(localAddr, port);
                    listener.Start();

                    while (listener != null)
                    {
                        if (listener.Pending())
                        {
                            TcpClient client = listener.AcceptTcpClient();

                            Task task = new Task((obj) => ProcessClient(obj), client);
                            task.Start();
                            clientTasks.Add(task);
                        }
                    }
            }

            private void ProcessClient(object obj)
            {
                    using (TcpClient client = obj as TcpClient)
                    {

                    Byte[] bytes = new Byte[2048];
                    String data = null;

                    NetworkStream stream = client.GetStream();
                    int i;

                    while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        data = Encoding.ASCII.GetString(bytes, 0, i);
                    }

                    // do some stuff with data
                    // If an exception is thrown here, the rogue thread issue happens when I stop the service. 
                    // Otherwise, everything is good - I stop the service and no rogue thread, I can reuse the listener port. 
                    }
            }
        }

РЕДАКТИРОВАТЬ: Обновлен код с предлагаемыми изменениями.Я также обнаружил, что эта проблема с неконтролируемыми потоками возникает только в том случае, если в одном из моих клиентских потоков возникло исключение.Если все работает нормально, то нет остановки мошенника, когда я останавливаю службу.

1 Ответ

0 голосов
/ 05 июня 2018

Стоп означает остановку текущего соединения и начало прослушивания нового, поэтому убедитесь, что ваш клиент правильно закрыт, чтобы новое соединение не создавалось.

Метод Stop также закрывает основной сокети создает новый сокет для TcpListener.Если вы установите какие-либо свойства в базовом сокете до вызова метода Stop, эти свойства не будут перенесены в новый сокет.

https://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.stop(v=vs.110).aspx#

Более того, убедитесь, что выиспользуйте using с клиентом

using(TcpClient client = obj as TcpClient){//DO SOMETHING}
...