Сервер сокетов Netcore не закрывается - PullRequest
0 голосов
/ 26 апреля 2020

Привет всем. Я разрабатываю довольно простой Socket Server для .NetCore. Этот сервер должен разрешить несколько клиентов и начать чтение с них, пока он не отменен.

Вот его код:

public class ClientHandler
    {
        public ClientHandler(Socket workSocket, int bufferSize)
        {
            WorkSocket = workSocket;
            BufferSize = bufferSize;
            receiveBuffer = new byte[BufferSize];
            currentBuffer = new byte[0];
        }

        public Socket WorkSocket { get; }
        // Size of receive buffer.
        public int BufferSize { get; }
        // Receive buffer.
        public byte[] receiveBuffer { get; set; }
        // Received data.
        public byte[] currentBuffer { get; set; }
    }


    public class MyServer
    {
        public MyServer(string ipAddress, int port,
            IProtocolParser parser, CancellationToken token, ILogger logger)
        {
            _ipAddress = ipAddress;
            _port = port;
            InternalCts = new CancellationTokenSource();
            _token = InternalCts.Token;
            _parser = parser;
            _logger = logger.ForContext(GetType());
        }

        private const int BUFFER_SIZE = 1024;
        private readonly IProtocolParser _parser;
        private readonly ILogger _logger;
        private readonly int _port;
        private readonly string _ipAddress;
        private readonly CancellationToken _token;
        private readonly ManualResetEvent _allDone = new ManualResetEvent(false);

        private CancellationTokenSource InternalCts { get; set; }        
        private Socket Server { get; set; }        

        public void Start()
        {
            try
            {
                var ipAddress = IPAddress.Parse(_ipAddress);
                var endpoint = new IPEndPoint(ipAddress, _port);

                _logger.Debug("Creating Socket Server On {ipAddress}:{port}", _ipAddress, _port);
                Server = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                Server.Bind(endpoint);
                Server.Listen(10);                                

                while(!_token.IsCancellationRequested)
                {
                    _allDone.Reset();
                    _logger.Debug("Waiting For Client");
                    Server.BeginAccept(AcceptCallback, Server);
                    _logger.Debug("Waiting One!");
                    _allDone.WaitOne();
                    _logger.Debug("Begin Accept Finished");
                }

                _logger.Debug("Task Finished!");
                return;
            }
            catch (Exception e)
            {
                _logger.Error("error");
            }
        }

        private void AcceptCallback(IAsyncResult ar)
        {
            // Signal the main thread to continue.
            _allDone.Set();

            // Get the socket that handles the client request.
            var listener = (Socket)ar.AsyncState;
            var handler = listener.EndAccept(ar);

            // Create the state object.
            var client = new ClientHandler(handler, BUFFER_SIZE);
            handler.BeginReceive(client.receiveBuffer, 0, client.BufferSize, 0,
                new AsyncCallback(ReadCallback), client);
        }

        private void ReadCallback(IAsyncResult ar)
        {
            // Retrieve the state object and the handler socket
            // from the asynchronous state object.
            var client = (ClientHandler)ar.AsyncState;
            var handler = client.WorkSocket;

            // Read data from the client socket. 
            var bytesRead = handler.EndReceive(ar);

            if (bytesRead > 0)
            {
                client.currentBuffer = ArrayExtensions.Combine(
                    client.currentBuffer, client.receiveBuffer.SubArray(0, bytesRead));

                var (message, newBuffer) = _parser.UnpackMessage(client.currentBuffer);

                if (!string.IsNullOrEmpty(message))
                {
                    _logger.Debug("New Message Received: {message}", message);
                }

                client.currentBuffer = newBuffer;
            }

            if (!_token.IsCancellationRequested)
            {
                // Not all data received. Get more.
                handler.BeginReceive(client.receiveBuffer, 0, client.BufferSize, 0,
                new AsyncCallback(ReadCallback), client);
            }
        }

        public void Stop()
        {            
            InternalCts.Cancel();            
            _logger.Debug("Stopping Server...");
            _logger.Debug("Closing Socket...");
            Server.Close();
            _allDone.Set();
            _logger.Debug("Socket Closed!");
        }
    }

И это основная программа:

static void Main(string[] args)
        {
            var parser = new VenomOEMProtocolParser();
            var cts = new CancellationTokenSource();
            var logger = new LoggerConfiguration()
                .MinimumLevel.Verbose()
                .Enrich.FromLogContext()
                .Enrich.WithThreadId()
                .WriteTo.Console().CreateLogger();

            var venomOem = new VenomOEM("192.168.0.107", 100, parser, cts.Token, logger);

            AppDomain.CurrentDomain.ProcessExit += (s, e) =>
            {
                venomOem.Stop();
            };

            Console.CancelKeyPress += delegate
            {
                venomOem.Stop();
            };

            try
            {
                venomOem.Start();
                logger.Debug("FINISHED!");
            }
            catch (OperationCanceledException oce)
            {
                logger.Debug(oce, "Operation Canceled Exception");
            }
            catch (Exception e)
            {
                logger.Error(e, "Unexpected Exception!");
            }
        }

Как вы можете видеть, я запускаю сервер и останавливаю его, когда на консольном приложении нажимаются клавиши Ctrl + C, и метод stop исключается, но приложение как-то зависает и не закрывается. Я думаю, что это связано с событиями сброса, но не может найти проблему.

Есть предложения?

Спасибо!

...