代码之家  ›  专栏  ›  技术社区  ›  Maciek

套接字ObjectDisposed异常

  •  5
  • Maciek  · 技术社区  · 14 年前

    在我的项目中,我有一个使用TcpListener接受传入连接的服务器类。

     public class Connection : ConnectionBase<Coder.Coder>
        {
            public Connection(TcpClient client, Guid id) : base()
            {
                Id = id;
                Client = client;
            }
    
            public void Start()
            {
                IsConnected = true;            
                Client.Client.BeginReceive(m_message, 0, m_message.Length, SocketFlags.None, new AsyncCallback(on_data_received), null);            
            }
    
            public void Stop()
            {
                try
                { 
                    Client.Close();
                    handle_connection_lost(new ConnectionLostArgs(Id));
                }
                catch
                { }
            }
    
            public void Send(byte[] data)
            {
                try
                {
                    using (NetworkStream s = Client.GetStream())
                    {
                        using (BinaryWriter w = new BinaryWriter(s))
                        {
                            var buffer = m_coder.Encode(data);
                            w.Write(buffer);
                            w.Flush();
                        }
                    }
    
                }
                catch
                { handle_connection_lost(new ConnectionLostArgs(Id)); }
            }
    
            public Guid Id { get; set; }
            public TcpClient Client { get; set; }
    
            private byte[] m_message = new byte[1024];        
    
            private void on_data_received(IAsyncResult ar)
            {
                try
                {
                    Client.Client.BeginReceive(m_message, 0, m_message.Length,
                            SocketFlags.None, new AsyncCallback(on_data_received), null);
    
                    int bytesRead = Client.Client.EndReceive(ar);
    
                    if (bytesRead > 0)
                    {
                        byte[] data = new byte[bytesRead];
                        Array.Copy(m_message, data, bytesRead);
    
                        m_coder.Push(data);
    
                    }               
                }
                catch(Exception ex)
                {
                    Console.WriteLine("Connection::on_data_received : {0}", ex.Message);
                    handle_connection_lost(new ConnectionLostArgs(Id));
                }
            }
    
            protected override void Dispose(bool disposing)
            {
                if (disposing)
                {
                    try
                    {
                        Stop();
                    }
                    catch
                    { }
                }
    
                base.Dispose(disposing);
            }
        }
    

    *请注意,编码器是负责解码和编码数据包的类。

    除上述内容外,我还有一个基于socket的TcpClient(我希望以后在Silverlight中重用它),代码如下:

     public class TcpSocketClient : TcpClientBase<Coder.Coder>
        {
            public static TcpSocketClient Create(string host, int port)
            {            
                if (port == 0)
                    return null;
    
                return new TcpSocketClient(host, port);
            }
    
            private TcpSocketClient(string host, int port) : base()
            {
                IsConnected = false;
                RemoteEndpoint = new DnsEndPoint(host, port);
            }
    
            public void Start()
            {
                m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
                byte[] buffer = new byte[1024];
    
                SocketAsyncEventArgs e = new SocketAsyncEventArgs()
                {
                    RemoteEndPoint = RemoteEndpoint,
                    UserToken = m_socket,
    
                };
                e.SetBuffer(buffer, 0, buffer.Length);
                e.Completed += new EventHandler<SocketAsyncEventArgs>(handle_socket_connect_completed);
    
                m_socket.ConnectAsync(e);
            }        
    
            public void Stop()
            {
                try
                {
                    m_socket.Close();
                    m_socket.Dispose();
                }
                catch (ObjectDisposedException)
                { }
            }
    
            public void Send(byte[] data)
            {
                try
                {
                    var buffer = m_coder.Encode(data);
                    SocketAsyncEventArgs e = new SocketAsyncEventArgs()
                    {
                        BufferList = new List<ArraySegment<byte>>() { new ArraySegment<byte>(buffer) },
                        UserToken = m_socket
                    };
                    m_socket.SendAsync(e);                
                }
                catch (Exception ex)
                { handle_client_disconnected(ex.Message); }
            }
    
            #region Properties
            public DnsEndPoint RemoteEndpoint { get; private set; }
            #endregion
    
            #region Fields
            Socket m_socket;
            #endregion
    
            void handle_socket_connect_completed(object sender, SocketAsyncEventArgs e)
            {
                if (!m_socket.Connected)
                {
                    handle_client_disconnected("Failed to connect");
                    return;
                }
    
    
                e.Completed -= handle_socket_connect_completed;
                e.Completed += new EventHandler<SocketAsyncEventArgs>(handle_socket_async_receive);
    
                handle_client_connected();
    
                m_socket.ReceiveAsync(e);                        
            }
    
            void handle_socket_async_receive(object sender, SocketAsyncEventArgs e)
            {
                if (e.BytesTransferred == 0)
                {
                    handle_client_disconnected("Connection closed by the remote host");
                    try { m_socket.Close(); }
                    catch { }
                    return;
                }
    
                try 
                {
                    byte[] buffer = new byte[e.BytesTransferred];
                    Array.Copy(e.Buffer, buffer, e.BytesTransferred);
                    m_coder.Push(buffer);                
                }
                catch { }
    
    
                m_socket.ReceiveAsync(e);            
            }
    
            protected override void Dispose(bool disposing)
            {
                if (disposing)
                {
                    try
                    {
                        RemoteEndpoint = null;
                        m_socket.Close();
                        m_socket.Dispose();
                    }
                    catch
                    { }
                }
    
                base.Dispose(disposing);
            }
        }
    

    在其中一个测试中,我将数据从客户机发送到服务器。作品。 在另一个测试中,我将数据从服务器连接发送到客户机。史诗般的失败。 我一直在收到数据时收到连接中的套接字ObjectDisposed异常。老实说,我不知道发生了什么事,所以我需要一些帮助。

    我使用的是.NET4,VS2010,我的机器的操作系统是Win7(如果这个信息有帮助的话)

    当做,

    2 回复  |  直到 14 年前
        1
  •  2
  •   Maciek    14 年前

    我终于明白了。

    public void Send(byte[] data)
            {
                try
                {
                    using (NetworkStream s = Client.GetStream())
                    {
                        using (BinaryWriter w = new BinaryWriter(s))
                        {
                            var buffer = m_coder.Encode(data);
                            w.Write(buffer);
                            w.Flush();
                        }
                    }
    
                }
                catch
                { handle_connection_lost(new ConnectionLostArgs(Id)); }
            }
    

    当释放(thx到using关键字)BinaryWriter或NetworkStream时,套接字将被释放(我不确定这是否是所需的行为),从而断开连接。去掉“使用”条款就解决了这个问题。

        2
  •  1
  •   Jeff Cyr    14 年前

    在你的 on_data_received 汉德勒,你在打电话吗 Client.Client.BeginReceive(...) 之前 Client.Client.EndReceive(...)

    BeginReceive可能会同步完成,导致异常并处理您的 Connection ,所以应该在EndReceive之后调用它。

        private void on_data_received(IAsyncResult ar)
        {
            try
            {
                int bytesRead = Client.Client.EndReceive(ar);
    
                if (bytesRead > 0)
                {
                    byte[] data = new byte[bytesRead];
                    Array.Copy(m_message, data, bytesRead);
    
                    m_coder.Push(data);
    
                    Client.Client.BeginReceive(m_message, 0, m_message.Length,
                        SocketFlags.None, new AsyncCallback(on_data_received), null);
                }
                else
                {
                    //TODO Close the connection
                }
    
            }
            catch(Exception ex)
            {
                Console.WriteLine("Connection::on_data_received : {0}", ex.Message);
                handle_connection_lost(new ConnectionLostArgs(Id));
            }
        }