套接字上的System.ObjectDisposedException以及何时关闭流

时间:2015-11-22 18:04:42

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

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

我的问题是,当我尝试读取套接字时,我收到了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来自客户端中的代码。问题解决了。

断开检测工作,以及反序列化。

我的问题是:我应该何时关闭该流?

1 个答案:

答案 0 :(得分:0)

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

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

您应该期望Socket上的任何操作都会针对意外错误抛出SocketException期望正常断开连接的消息正好为0字节。

我没有那么多使用BinaryReader,但我希望它会在EndOfStreamException处抛出int length = reader.ReadInt32();