CryptoStream i NetworkStream - automatyczne zamykanie połączenia

0

Witam. Mam pewien problem nad którym się już trochę zastanawiam. Piszę grę multiplayer - w tym celu tworzę aplikację klienta i serwera. Aby przekazać dane pomiędzy nimi wykorzystuję napisaną przeze mnie klasę pakietu, którą później poddaję serializacji i przepuszczam przez CryptoStream "połączony" z NetworkStream. Metody Read i Write:

            public static void Write(object obj, ref NetworkStream ns, Aes aes)
            {
                ICryptoTransform crypter = aes.CreateEncryptor(aes.Key, aes.IV);

                using (CryptoStream cs = new CryptoStream(ns, crypter, CryptoStreamMode.Write))
                {
                    try
                    {
                        new BinaryFormatter().Serialize(cs, obj);
                    }
                    catch (Exception ex)
                    {
                        System.Windows.Forms.MessageBox.Show(ex.ToString());
                    }
                }
            }

            public static object Read(ref NetworkStream ns, Aes aes)
            {
                ICryptoTransform crypter = aes.CreateDecryptor(aes.Key, aes.IV);

                object obj = null;

                using (CryptoStream cs = new CryptoStream(ns, crypter, CryptoStreamMode.Read))
                {
                    try
                    {
                        obj = new BinaryFormatter().Deserialize(cs);
                    }
                    catch (Exception ex)
                    {
                        System.Windows.Forms.MessageBox.Show(ex.ToString());
                    }
                }

                return obj;
            }

Nie wiem dlaczego, lecz zawsze po zakończeniu wykonywania bloku using NetworkStream jak i TcpClient umieszczony w innej klasie traci połączenie z serwerem. Próbowałem wielu rzeczy: pomijałem blok using, usuwałem polecenie cs.Close() (było ono umieszczone wcześniej, aktualnie nie jest), usuwałem "ref" z parametru, lecz ciągle otrzymuję ten komunikat:

Nawiązane połączenie zostało przerwane przez oprogramowanie zainstalowane w komputerze-hoście.

Aktualnie (i co jest dziwne) tego komunikatu nie otrzymuję, lecz problem się nadal utrzymuje. Nie wiem co może to powodować: próbowałem wyłączyć i antywirusa i zaporę, lecz to nie pomaga (klient i serwer testuję na tym samym komputerze). Bawię się z tym już 4 godziny i nie mogę znaleźć rozwiązania - raczej na pewno połączenie się zapada w tych metodach (obie są wykorzystywane i na serwerze i na kliencie).

Tak a propos, jedno pytanie: mogę podawać TcpClient i NetworkStream w parametrach konstruktora?

Pozdrawiam.

EDIT: Chyba znalazłem usterkę. Błąd występuje nie tylko wtedy, gdy klient i serwer korzystają w tej samej chwili z powyższych metod, ale także gdy serwer korzysta z tej metody podając za NetworkStream obiekt leżący "poza metodą" (w sensie poza taskiem, gdyż jest w nim wykonywany). Czy przez taką operację połączenie może się zamykać?

0

Z góry przepraszam za multi-post, ale wydaje mi się odpowiedniejszą formą napisanie nowego postu :).

Problem naprawiłem w sumie po 6 godzinach :D. Wygląda na to, że nie można bezpośrednio połączyć NetworkStream i CryptoStream, gdyż od razu spowoduje to zakończenie połączenia (po prostu NetworkStream uznawany jest za strumień bardziej "nieskończony" i program ciągle czeka na nowe dane - bez zakończenia połączenia trwałoby to w nieskończoność. Dlatego między innymi nie da się skopiować NetworkStream do MemoryStream metodą CopyTo - wykonanie metody trwałoby w nieskończoność).

Zmodyfikowałem moje metody tak, że pośrednikiem pomiędzy CryptoStream a NetworkStream jest MemoryStream:

            public static void Write(object obj, ref NetworkStream ns, Aes aes)
            {
                BinaryFormatter bf = new BinaryFormatter();
                ICryptoTransform crypter = aes.CreateEncryptor();


                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, crypter, CryptoStreamMode.Write))
                    {
                        try
                        {
                            bf.Serialize(cs, obj);
                        }
                        catch (Exception ex)
                        {
                            System.Windows.Forms.MessageBox.Show(ex.ToString());
                        }

                        cs.Close();
                    }

                    Byte[] buffer = ms.ToArray();

                    ns.Write(buffer, 0, buffer.Length);

                    ms.Close();
                }
            }

            public static object Read(ref NetworkStream ns, Aes aes)
            {
                BinaryFormatter bf = new BinaryFormatter();
                ICryptoTransform crypter = aes.CreateDecryptor();

                object obj = null;

                Byte[] data = new Byte[1024000];
                int bytes = ns.Read(data, 0, data.Length);

                using (MemoryStream ms = new MemoryStream(data, 0, bytes))
                {
                    using (CryptoStream cs = new CryptoStream(ms, crypter, CryptoStreamMode.Read))
                    {
                        obj = bf.Deserialize(cs);

                        cs.Close();
                    }

                    ms.Close();
                }

                return obj;
            }

Teraz wszystko działa jak należy :).

Pozdrawiam.

1 użytkowników online, w tym zalogowanych: 0, gości: 1