首页 > 解决方案 > C# 异步 TCP 客户端在服务器断开连接后进入无限循环

问题描述

我的代码有问题。很容易,我在这里写了一个问题。

我编写了一个新类来拥有一个异步 TCP 客户端。我的问题很简单,在服务器断开连接时,接收回调在无限循环中调用,没有读取任何字节。项目的 RAM 是指数级的。这对我来说太不可思议了,我没有一点线索来解决这个问题..我尝试了很多解决方案来解决这个问题,但没有成功......

我是代码新手..

服务器断开连接后的ram

public class TcpClientAsync : IDisposable
{
    ////////////////////////////////////////////////////////////////
    /// Constant
    #region Constant
    private const string SOURCE = "TcpClient";
    #endregion

    /////////////////////////////////////////////////////////////////////
    /// Constructor
    #region Constructor
    public TcpClientAsync()
    {
        mpr_timeoutConnection.Elapsed += Mpr_timeoutConnection_Elapsed;
        mpr_timeoutConnection.AutoReset = false;

    }

    ~TcpClientAsync()
    {
        StopAndClean();
    }

    #endregion

    /////////////////////////////////////////////////////////////////////
    /// Private Member
    #region Private Member
    private IPAddress mpr_remoteIp = IPAddress.Any;
    private IPEndPoint mpr_remoteEndPoint;
    private Socket mpr_clientSocket;
    private Timer mpr_timeoutConnection = new Timer(5000);
    private bool mpr_checkFrameSize = false;

    #endregion

    /////////////////////////////////////////////////////////////////////
    /// Protected Member
    #region Protected Member

    #endregion

    /////////////////////////////////////////////////////////////////////
    /// Public Member
    #region Public Member


    #endregion

    /////////////////////////////////////////////////////////////////////
    /// EventHandler
    #region EventHandler
    public event EventHandler<Frame> OnNewDataReceived = delegate { };
    public event EventHandler<TcpClientState> OnNewState = delegate { };
    public event EventHandler<Event> OnNewEvent = delegate { };
    public event EventHandler<EndPoint> OnBeginConnect = delegate { };
    public event EventHandler<EndPoint> OnConnect = delegate { };
    public event EventHandler OnDisconnect = delegate { };
    public event EventHandler<Frame> OnNewDataSent = delegate { };

    #endregion

    /////////////////////////////////////////////////////////////////////
    /// Properties
    #region Properties

    public double ConnectionTimeout
    {
        get
        {
            return mpr_timeoutConnection.Interval;
        }
        set
        {
            mpr_timeoutConnection.Interval = value;
        }
    }

    public bool CheckFrameSize
    {
        get { return mpr_checkFrameSize; }
        set
        {
            mpr_checkFrameSize = value;
        }
    }
    #endregion

    ////////////////////////////////////////////////////////////////////
    /// Event Callback
    #region EventCallback
    private void Mpr_timeoutConnection_Elapsed(object sender, ElapsedEventArgs e)
    {
        OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Timeout for connection", "Timeout for connect remote tcp server."));
        StopAndClean();
        mpr_timeoutConnection.Enabled = false;
    }

    #endregion

    ////////////////////////////////////////////////////////////////////
    // Private Method
    #region Private Method
    private void StartService(int port = 2401, string remoteAddress = "0.0.0.0")
    {
        try
        {
            try
            {
                if (!IPAddress.TryParse(remoteAddress, out mpr_remoteIp))
                {
                    OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Warning, "Fail to parse ip address", "Try to retrieve by hostname"));
                    IPHostEntry ipHostInfo = Dns.GetHostEntry(remoteAddress);
                    if (ipHostInfo == null)
                    {
                        OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Error for retrieve remote end point", ""));
                        StopAndClean();
                        return;
                    }

                    mpr_remoteIp = ipHostInfo.AddressList[0];
                }

                mpr_remoteEndPoint = new IPEndPoint(mpr_remoteIp, port);
            }
            catch (Exception ex)
            {
                OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Error for retrieve remote endpoint", ex.Message, ex));
                StopAndClean();
                return;
            }

            try
            {
                // Create a TCP/IP socket.  
                mpr_clientSocket = new Socket(mpr_remoteIp.AddressFamily,
                    SocketType.Stream, ProtocolType.Tcp);

                try
                {
                    // Connect to the remote endpoint.  
                    mpr_clientSocket.BeginConnect(mpr_remoteEndPoint,
                        new AsyncCallback(ConnectCallback), mpr_clientSocket);

                    OnBeginConnect?.Invoke(this, mpr_remoteEndPoint);
                    OnNewState?.Invoke(this, TcpClientState.ConnectionInProgress);
                    if (mpr_timeoutConnection.Enabled)
                        mpr_timeoutConnection.Enabled = false;
                    mpr_timeoutConnection.Enabled = true;

                }
                catch (Exception ex)
                {
                    OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Error to launch connection", ex.Message, ex));
                    StopAndClean();
                    return;
                }
            }
            catch (Exception ex)
            {
                OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Error to create or launch socket connection", ex.Message, ex));
                StopAndClean();
                return;
            }

        }
        catch (Exception ex)
        {
            OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Fail to start tcp client", ex.Message, ex));
            StopAndClean();
            return;
        }
    }

    private void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            try
            {
                // Retrieve the socket from the state object.  
                Socket client = (Socket)ar.AsyncState;

                // Complete the connection.  
                client.EndConnect(ar);

                try
                {
                    // Set new state
                    mpr_timeoutConnection.Enabled = false;
                    OnNewState?.Invoke(this, TcpClientState.Connected);
                    OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Event, "Remote partner connected : " + client.RemoteEndPoint.ToString(), ""));
                    OnConnect?.Invoke(this, client.RemoteEndPoint);

                    // Make receive callback
                    try
                    {
                        // Create the state object.  
                        StateObject state = new StateObject();
                        state.workSocket = client;

                        // Begin receiving the data from the remote device.  
                        mpr_clientSocket.BeginReceive(state.frame.FrameBytes, 0, StateObject.BufferSize, 0,
                            new AsyncCallback(ReceiveCallback), state);
                    }
                    catch (Exception ex)
                    {
                        OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Fail to create receive callback", ex.Message, ex));
                        StopAndClean();
                        return;
                    }
                }
                catch (Exception ex)
                {
                    OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Fail to update the state", ex.Message, ex));
                    StopAndClean();
                    return;
                }
            }
            catch (Exception ex)
            {
                OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Fail to stop connection state", ex.Message, ex));
                StopAndClean();
                return;
            }
        }
        catch (Exception ex)
        {
            OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Fail to open the connection with server", ex.Message, ex));
            StopAndClean();
            return;
        }
    }

    private void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            try
            {
                // Retrieve the state object and the client socket
                // from the asynchronous state object.  
                StateObject state = (StateObject)ar.AsyncState;
                Socket client = state.workSocket;

                // Read data from the remote device.  
                int bytesRead = client.EndReceive(ar);

                try
                {
                    
                    if (bytesRead > 0)
                    {
                        state.sb.Append(Encoding.ASCII.GetString(
                            state.frame.FrameBytes, 0, bytesRead));

                        if (bytesRead != StateObject.BufferSize && mpr_checkFrameSize)
                        {
                            OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Incomplete frame received from component, frame size expected : " + StateObject.BufferSize.ToString(), ""));
                            OnNewDataReceived?.Invoke(this, state.frame);
                            StopAndClean();
                            return;
                        }

                    }
                    else
                    {
                        OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Warning, "Empty frame received from component", ""));
                    }
                }
                catch (Exception ex)
                {
                    OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Fail to encode received frame", ex.Message, ex));
                    StopAndClean();
                    return;
                }

                try
                {
                    OnNewDataReceived?.Invoke(this, state.frame);
                }
                catch (Exception ex)
                {
                    OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Fail to share received data", ex.Message, ex));
                    StopAndClean();
                    return;
                }

                try
                {
                    // Create new callback for a new incoming frame
                    StateObject newState = new StateObject();
                    newState.workSocket = client;

                    client.BeginReceive(newState.frame.FrameBytes, 0, StateObject.BufferSize, 0,
                        new AsyncCallback(ReceiveCallback), newState);

                }
                catch (Exception ex)
                {
                    OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Fail to create receive callback", ex.Message, ex));
                    StopAndClean();
                    return;
                }
            }
            catch (Exception ex)
            {
                OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Fail to close socket for read buffer", ex.Message, ex));
                StopAndClean();
                return;
            }
        }
        catch (Exception ex)
        {
            OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Fail to receive data from server", ex.Message, ex));
            StopAndClean();
            return;
        }
    }

    private void Send(Socket client, Frame data)
    {
        if (!mpr_clientSocket.Connected)
        {
            OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Warning, "Fail to send frame, not connected", ""));
            return;
        }

        try
        {
            // Create state object
            StateObject state = new StateObject();
            state.workSocket = client;

            // Convert the string data to byte data using ASCII encoding.  
            state.frame = data;

            try
            {
                // Begin sending the data to the remote device.  
                client.BeginSend(state.frame.FrameBytes, 0, state.frame.Lenght, 0,
                    new AsyncCallback(SendCallback), state);
            }
            catch (Exception ex)
            {
                OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Error for create the send callback", ex.Message, ex));
                StopAndClean();
                return;
            }
        }
        catch (Exception ex)
        {
            OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Fail to create the send callback", ex.Message, ex));
            StopAndClean();
            return;
        }

    }

    private void SendCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the socket from the state object.  
            StateObject state = (StateObject)ar.AsyncState;
            Socket handler = state.workSocket;

            // Complete sending the data to the remote device.  
            int bytesSent = handler.EndSend(ar);

            // Update hex dump
            OnNewDataSent?.Invoke(this, state.frame);
        }
        catch (Exception ex)
        {
            OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Error in send callback", ex.Message, ex));
            StopAndClean();
            return;
        }
    }


    private void StopAndClean()
    {
        if (mpr_clientSocket != null)
        {
            if (mpr_clientSocket.Connected)
            {
                OnDisconnect?.Invoke(this, EventArgs.Empty);
                mpr_clientSocket.Shutdown(SocketShutdown.Both);
            }

            mpr_clientSocket.Close();
            mpr_clientSocket.Dispose();
        }

        OnNewState?.Invoke(this, TcpClientState.Disconnect);

        mpr_timeoutConnection.Enabled = false;

    }
    #endregion

    ////////////////////////////////////////////////////////////////////
    // Protected Method
    #region Protected Method

    #endregion

    ////////////////////////////////////////////////////////////////////
    // Public Method
    #region Public Method

    public void Start(int port = 2401, string ipAddress = "0.0.0.0")
    {
        try
        {
            StartService(port, ipAddress);
        }
        catch (Exception ex)
        {
            OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Error to start the client", ex.Message, ex));
            StopAndClean();
            return;
        }
    }

    public void Stop()
    {
        try
        {
            StopAndClean();
        }
        catch (Exception ex)
        {
            OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Error to stop the client", ex.Message, ex));
            StopAndClean();
            return;
        }
    }

    public void SendFrame(Frame frame)
    {
        try
        {
            Send(mpr_clientSocket, frame);
        }
        catch (Exception ex)
        {
            OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Error, "Error to send frame", ex.Message, ex));
            StopAndClean();
            return;
        }
    }

    public void Dispose()
    {
        StopAndClean();
    }

    #endregion
}

标签: c#loopsasynchronoustcpclient

解决方案


推荐阅读