简体   繁体   中英

System.ObjectDisposedException on a socket and when to close streams

I'm trying to code a client-server communication. So far, i manage to connect in a first thread. A second thread read the socket and a third one check if there is no unexpected disconection from a client.

My problem is that i got a System.ObjectDisposedException when i try to read the socket. If i continue the running of the program (ignoring the exception), the same exception happens when i check if the socket is still connected.

The server is a class with the following fields :

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 is used in the socket reader thread (last sample of code in this message) acceptList contains the results of Socket.Accept(). Here is how acceptList is filled.

 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;
        }
    }

Now here is how i check if there wasn't any unexpected disconnection from the client :

            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);
            }

And the last part of code i need to show if how i read my socket.

    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();
                            }
                        }
                    }
                }
            }

I realised that maybe my socket was closed by the line ns.Close(), and that cause the error. With ns.Close(), I just attempted to close the stream I created to get the datas from the socket, and not close the socket itself. I tried to remove that ns.Close() line, and the ObjectDisposedException doesn't appear anymore ! However, now i got an OutOfMemoryException at the line :

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

in the reading thread. I believe this exception is caused because the stream isn't closed.

EDIT : The OutOfMemoryException comes from code in the client. Problem solved here.

The disconnection detection works, and the deserialization too.

My question is : When should i close that stream ??

When using Socket.Select , there's really no need for an additional thread - just include the sockets in the checkError parameter as well as in the checkRead parameter.

It might look like the disconnection bit works, because during your test it closed your socket, but my guess is that the remote connection actually sent a valid disconnect (as opposed to an "unexpected" disconnect) message, causing your read thread to choke on the now closed socket.

You should expect any operation on a Socket to throw a SocketException for unexpected errors, and expect a message of exactly 0 bytes for a regular disconnect.

I don't use BinaryReader that much but I'd expect it to throw an EndOfStreamException at int length = reader.ReadInt32(); .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM