无法停止异步TCP服务器Windows服务

Tom*_*Tom 12 .net c# sockets windows-services tcp

我有一个在.net 4.0中使用异步服务器套接字开发的TCP服务器Windows服务.

它工作,但大约90%的时间我根本无法阻止它:在Windows服务控制台中按停止按钮后,它会在大约一分钟后挂起并停止,但其过程继续,TCP通信继续.它挂在_listener.Close().我只能重新启动Windows才能关闭通信.关闭套接字可能有些东西.我试图搞清楚,但我根本找不到问题的根源.

客户端不在我的控制之下,它们是通过TCP发送数据的大约100个小工具.

这是我的代码(更新).

非常感谢,任何建议都非常感谢!

    public class DeviceTCPServer
{
    public readonly IPAddress IPAddress;
    public readonly int Port;
    public readonly int InputBufferSize;
    public readonly ConcurrentDictionary<Guid, StateObject> Connections;

    public event EventHandler OnStarted;
    public event EventHandler OnStopped;
    public event ServerEventHandler OnConnected;
    public event ServerEventHandler OnDisconnected;
    public event RecievedEventHandler OnRecieved;
    public event DroppedEventHandler OnDropped;
    public event ExceptionEventHandler OnException;
    public event ServerLogEventHandler ServerLog;

    private volatile bool _iAmListening;
    private Socket _listener;
    private Thread _listenerThread;
    private readonly ManualResetEvent _allDone = new ManualResetEvent(false);

    public bool Listening
    {
        get { return _iAmListening; }
    }

    public DeviceTCPServer(IPAddress ipAddress,
                         int port,
                         int inputBufferSize)
    {
        IPAddress = ipAddress;
        Port = port;
        InputBufferSize = inputBufferSize;

        Connections = new ConcurrentDictionary<Guid, StateObject>();
    }

    public void ThreadedStart()
    {
        _listenerThread = new Thread(Start)
        {
            CurrentUICulture = Thread.CurrentThread.CurrentUICulture,
            IsBackground = true
        };

        _listenerThread.Start();
    }

    private void Start()
    {
        try
        {
            var localEP = new IPEndPoint(IPAddress, Port);
            _listener = new Socket(localEP.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            _listener.Bind(localEP);
            _listener.Listen(10000);

            if (OnStarted != null)
                OnStarted(this, new EventArgs());

            _iAmListening = true;

            var listenerWithCultureInfo = new Tuple<Socket, CultureInfo>(_listener,
                                                                         Thread.CurrentThread.CurrentUICulture);

            while (_iAmListening)
            {
                _allDone.Reset();
                _listener.BeginAccept(AcceptCallback, listenerWithCultureInfo);
                _allDone.WaitOne();
            }
        }
        catch (Exception exc)
        {
            Debug.Assert(false, exc.Message);
            if (OnException != null)
                OnException(this, new ExceptionEventArgs(exc, "Start"));
        }
    }

    public void StopListening()
    {
        try
        {
            _iAmListening = false;
            _allDone.Set();
        }
        catch(Exception exc)
        {
            Debug.Assert(false, exc.Message);
            if (OnException != null)
                OnException(this, new ExceptionEventArgs(exc, "StopListening"));
        }
    }

    public void Stop()
    {
        try
        {
            _listener.Close(0);
            CloseAllConnections();
            _listenerThread.Abort();
        }
        catch (Exception exc)
        {
            Debug.Assert(false, exc.Message);
            if (OnException != null)
                OnException(this, new ExceptionEventArgs(exc, "Stop"));
        }
    }

    private void AcceptCallback(IAsyncResult ar)
    {
        var arTuple = (Tuple<Socket, CultureInfo>)ar.AsyncState;
        var state = new StateObject(arTuple.Item2, InputBufferSize);

        try
        {
            Connections.AddOrUpdate(state.Guid,
                                    state,
                                    (k, v) => v);

            Thread.CurrentThread.CurrentUICulture = state.CurrentUICulture;

            var listener = arTuple.Item1;
            var handler = listener.EndAccept(ar);

            _allDone.Set();
            if (!_iAmListening)
                return;

            state.WorkSocket = handler;
            handler.BeginReceive(state.Buffer, 0, state.InputBufferSize, 0,
                                 RecieveCallBack, state);

            if (OnConnected != null)
                OnConnected(this, new ServerEventArgs(state));
        }
        catch(ObjectDisposedException)
        {
            _allDone.Set();
            return;
        }
        catch (Exception exc)
        {
            Debug.Assert(false, exc.Message);
            if (OnException != null)
                OnException(this, new ExceptionEventArgs(exc, state, "AcceptCallback"));
        }
    }

    public void RecieveCallBack(IAsyncResult ar)
    {
        var state = (StateObject)ar.AsyncState;

        try
        {
            Thread.CurrentThread.CurrentUICulture = state.CurrentUICulture;

            var handler = state.WorkSocket;
            var read = handler.EndReceive(ar);

            var pBinayDataPocketCodecStore = new BinayDataPocketCodecStore();

            if (read > 0)
            {
                state.LastDataReceive = DateTime.Now;

                var data = new byte[read];
                Array.Copy(state.Buffer, 0, data, 0, read);
                state.AddBytesToInputDataCollector(data);

                //check, if pocket is complete
                var allData = state.InputDataCollector.ToArray();
                var codecInitRes = pBinayDataPocketCodecStore.Check(allData);

                if (codecInitRes.Generic.Complete)
                {
                    if (!codecInitRes.Generic.Drop)
                    {
                        if (OnRecieved != null)
                            OnRecieved(this, new RecievedEventArgs(state, allData));
                    }
                    else
                    {
                        if (OnDropped != null)
                            OnDropped(this, new DroppedEventArgs(state, codecInitRes.Generic));

                        //get new data
                        state.ResetInputDataCollector();

                        handler.BeginReceive(state.Buffer, 0, state.InputBufferSize, 0,
                                             RecieveCallBack, state);
                    }
                }
                else
                {
                    //get more data
                    handler.BeginReceive(state.Buffer, 0, state.InputBufferSize, 0,
                                         RecieveCallBack, state);
                }
            }
            else
            {
                if ((handler.Connected == false) || (handler.Available == 0))
                {
                    Close(state);
                }
            }
        }
        catch (Exception exc)
        {
            Debug.Assert(false, exc.Message);
            if (OnException != null)
                OnException(this, new ExceptionEventArgs(exc, state, "RecieveCallBack"));
        }
    }

    public void Send(StateObject state, byte[] data)
    {
        try
        {
            var handler = state.WorkSocket;

            handler.BeginSend(data, 0, data.Length, 0,
                              SendCallback, state);
        }
        catch (Exception exc)
        {
            Debug.Assert(false, exc.Message);
            if (OnException != null)
                OnException(this, new ExceptionEventArgs(exc, state, "Send"));
        }
    }

    private void SendCallback(IAsyncResult ar)
    {
        var state = (StateObject)ar.AsyncState;

        try
        {
            Thread.CurrentThread.CurrentUICulture = state.CurrentUICulture;
            var handler = state.WorkSocket;

            handler.EndSend(ar);
            handler.BeginReceive(state.Buffer, 0, state.InputBufferSize, 0,
                                 RecieveCallBack, state);
        }
        catch (Exception exc)
        {
            Debug.Assert(false, exc.Message);
            if (OnException != null)
                OnException(this, new ExceptionEventArgs(exc, state, "SendCallback"));
        }
    }

    public void Close(StateObject state)
    {
        try
        {
            if (state == null)
                return;

            var handler = state.WorkSocket;

            if (handler == null)
                return;

            if (!handler.Connected)
                return;

            if (handler.Available > 0)
            {
                var data = new byte[handler.Available];
                handler.Receive(data);
            }

            handler.Shutdown(SocketShutdown.Both);
            handler.Close(0);

            if (OnDisconnected != null)
                OnDisconnected(this, new ServerEventArgs(state));

            StateObject removed;
            var removeResult = Connections.TryRemove(state.Guid, out removed);
        }
        catch (Exception exc)
        {
            Debug.Assert(false, exc.Message);
            if (OnException != null)
                OnException(this, new ExceptionEventArgs(exc, "Close"));
        }
    }

    private void CloseAllConnections()
    {
        try
        {
            var connections = Connections.Select(c => c.Value);

            foreach(var connection in connections)
            {
                Close(connection);
            }
        }
        catch(Exception exc)
        {
            Debug.Assert(false, exc.Message);
            if (OnException != null)
                OnException(this, new ExceptionEventArgs(exc, "CloseAllConnections"));
        }
    }

    public override string ToString()
    {
        return string.Format("{0}:{1}", IPAddress, Port);
    }
}
Run Code Online (Sandbox Code Playgroud)

Tom*_*Tom 0

所以,问题终于解决了,我的Windows服务没有任何问题!

\n\n

这是由 Microsoft Windows 更新引起的:

\n\n

Microsoft KB4338815,导致 closesocket t\xd0\xbe 在 Intel Xeon 处理器上永远挂起: https://forum.filezilla-project.org/viewtopic.php ?t=49308

\n\n

感谢您为帮助我所做的一切努力!

\n