【问题标题】:System.ObjectDisposedException on a socket and when to close streams套接字上的 System.ObjectDisposedException 以及何时关闭流
【发布时间】:2015-11-22 18:04:42
【问题描述】:

我正在尝试编写客户端-服务器通信。到目前为止,我设法在第一个线程中连接。第二个线程读取套接字,第三个线程检查是否没有来自客户端的意外断开连接。

我的问题是当我尝试读取套接字时出现 System.ObjectDisposedException。如果我继续运行程序(忽略异常),当我检查套接字是否仍然连接时会发生同样的异常。

服务器是一个具有以下字段的类:

static class Server
    {
        static ArrayList readList = new ArrayList();
        static ArrayList acceptList = new ArrayList();

        static public Thread thread1 = new Thread(new ThreadStart(SocketConnector));

        static Thread thread2 = new Thread(new ThreadStart(SocketListener));
        static Thread thread3 = new Thread(new ThreadStart(SocketClose));
        static Thread thread4 = new Thread(new ParameterizedThreadStart(SocketWriter));

readList 用于套接字读取器线程(此消息中的最后一个代码示例) acceptList 包含 Socket.Accept() 的结果。这是acceptList的填充方式。

 static void SocketConnector()
    {
     while (true)
     {
      sock.Listen(25);
      actif = sock.Accept();

      if (actif != null)
        {
          lock (acceptList)
            {
              acceptList.Add(actif);
              Console.WriteLine("IT WORKS");
              // that writeline appeared when i try to connect with the client.
            }
              actif = null;
        }
    }

现在这是我检查客户端是否没有意外断开连接的方法:

            static void SocketClose()
            {
             while (true)
             {
                for (int i = 0; i < acceptList.Count; ++i)
                {
                    if (((Socket)acceptList[i]).Poll(25, SelectMode.SelectRead) && ((Socket)acceptList[i]).Available == 0)
                    {


                           lock (acceptList)
                            { 
                               ((Socket)acceptList[i]).Close();
                                Console.WriteLine("Client " + ((Socket)acceptList[i]).GetHashCode() + " déconnecté");
                                acceptList.Remove((Socket)acceptList[i]);
                                i--;
                            }
                        }
                    }
                    Thread.Sleep(5);
            }

如果我如何读取我的套接字,我需要显示代码的最后一部分。

    static void SocketListener()
    { 
            while (true)
            {
                readList.Clear();
                lock (acceptList)
                {
                    for (int i = 0; i < acceptList.Count; i++)
                    {
                        readList.Add((Socket)acceptList[i]);
                    }
                }
                if (readList.Count > 0)
                {
                    Socket.Select(readList, null, null, 1000);

                    for (int i = 0; i < readList.Count; i++)
                    {
                        if (((Socket)readList[i]).Available > 0)
                        {
                            while (((Socket)readList[i]).Available > 0)
                            {
                                Console.WriteLine("Debut Deserialisation");

                                // get the underlying socket for the TcpClient
                                TcpClient client = new TcpClient();
                                client.Client = (Socket)readList[i];
                                NetworkStream ns = client.GetStream();
                                BinaryReader reader = new BinaryReader(ns);
                                Message received = new Message();

                                Console.WriteLine(received.msg);
                                Console.WriteLine(received.user);
                                Console.WriteLine(received.targetChatroom);


                               // Deserialisation
                                int length = reader.ReadInt32();
                                byte[] msgArray = reader.ReadBytes(length);
                                received.msg = Encoding.UTF8.GetString(msgArray);

                                length = reader.ReadInt32();
                                msgArray = reader.ReadBytes(length);
                                received.user = Encoding.UTF8.GetString(msgArray);

                                length = reader.ReadInt32();
                                msgArray = reader.ReadBytes(length);
                                received.targetChatroom = Encoding.UTF8.GetString(msgArray);

                               ns.Close();
                            }
                        }
                    }
                }
            }

我意识到我的套接字可能被 ns.Close() 行关闭了,这导致了错误。使用 ns.Close(),我只是试图关闭为从套接字获取数据而创建的流,而不是关闭套接字本身。我试图删除该 ns.Close() 行,并且 ObjectDisposedException 不再出现!但是,现在我在该行收到了 OutOfMemoryException :

byte[] msgArray = reader.ReadBytes(length);

在阅读线程中。我相信这个异常是因为流没有关闭造成的。

编辑:OutOfMemoryException 来自客户端中的代码。问题在这里解决了。

断线检测有效,反序列化也有效。

我的问题是:我应该什么时候关闭该流??

【问题讨论】:

  • 很多代码但仍然不完整。目前还不清楚它在哪个线程上运行,new Thread(new ThreadStart(SocketClose)); 看起来不是一个很棒的工具。您的阅读线程应该配合停止和关闭。
  • @Henk Holterman 你是对的。我编辑显示哪个代码示例属于哪个线程。 “SocketClose”线程是一个线程,如果其他主机在断开连接时没有向您发送数据包(例如,因为它不正常地断开连接),则检查套接字是否仍然连接。可能这个名字选得不太好。

标签: c# multithreading sockets out-of-memory objectdisposedexception


【解决方案1】:

使用Socket.Select 时,实际上不需要额外的线程 - 只需在checkError 参数和checkRead 参数中包含套接字即可。

它可能看起来断开连接位有效,因为在您的测试期间它关闭了您的套接字,但我的猜测是远程连接实际上发送了有效的断开连接(而不是“意外”断开连接)消息,导致您的读取线程窒息现在关闭的套接字。

您应该期望对 Socket 的任何操作都会因意外错误而引发 SocketException并且期望对于常规断开连接来说正好为 0 字节的消息。

我不经常使用BinaryReader,但我希望它会在int length = reader.ReadInt32(); 上抛出一个EndOfStreamException

【讨论】:

    猜你喜欢
    • 2013-02-13
    • 1970-01-01
    • 2013-07-17
    • 1970-01-01
    • 2015-11-03
    • 1970-01-01
    • 2018-12-11
    • 2011-04-26
    • 2020-03-20
    相关资源
    最近更新 更多