C#, gniazda, network programming i p2p

0

Witam,
Jestem w trakcie tworzenia komunikatora internetowego i w sumie wszystko przebiega całkiem dobrze. Program oparty jest aktualnie o komunikację klient-server i pytanie moje dotyczy zamiany typu tej komunikacji na p2p. Otóż nie bardzo wiem, jak poradzić sobie z załóżmy pierwszym odpalonym klientem. Jaką on rolę powinien pełnić? (Pewnie serwera) Ale skąd drugi klient ma rozpoznać, że to nie on jest serwerem? Nie bardzo rozumiem jak do tego podejść, stąd prośba o pomoc.
Bardzo dziękuje, pozdrawiam

0

Mam pewien zarys i chciałbym do przesyłania (komunikowania się) użyć serializacji. Mam jednak pewien problem. Nie wiedzieć czemu wyskakuje mi błąd zbyt małej ilości pamięci do przeprowadzenia deserializacji przy odbiorze wiadomości. Proszę o pomoc. Kod wygląda tak:
SERIALIZOWANA KLASA

 [Serializable]
    public class Status
    {
        public string naglowek { get; set; }
        public string login { get; set; }
        public string haslo { get; set; }
        public string ip { get; set; }
    }

STRONA KLIENTA

private void polacz()
        {
            Status nowy = new Status();
            nowy.login = textBox1.Text.ToString();
            nowy.haslo = textBox2.Text.ToString();

            IPHostEntry ip = Dns.GetHostEntry(Dns.GetHostName());
            IPAddress adres = ip.AddressList[0];
            nowy.ip = adres.ToString();
            //nowy.dostepni = null;
            nowy.naglowek = "";
            
            try
            {
                sox = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                sox.Connect(serwer);
                strumien = new NetworkStream(sox);
                format.Serialize(strumien, nowy);
                strumien.Flush();
            }
            catch (SocketException ex)
            {
                MessageBox.Show("Wystąpił błąd: " + ex);
            }
        }

STRONA SERWERA

private void nasluchuj()
        {
            byte[] msg = new byte[sizeof(Int64)];
            Socket zaakceptowany;
            Status nowy = new Status();

            try
            {
                klient.Bind(lokalne);
                while (true)
                {
                    klient.Listen(100);
                    zaakceptowany = klient.Accept();
                    strumien = new NetworkStream(zaakceptowany);
                    strumien.Read(msg, 0, msg.Length);
                    nowy = (Status)format.Deserialize(strumien);  // Tu wyskakuje błąd "Zgłoszono wyjątek typu 'System.OutOfMemoryException'."
                    SetText(nowy.login);
                    strumien.Flush();
                }
            }
            catch(SocketException ex)
            {
                MessageBox.Show("Wystąpił błąd: " + ex);
            }
        }

Dodam jeszcze, że jak robię tak, jak poniżej, to mi wyskakuje podczas deserializacji informacja o końcu deserializowanego strumienia :(

private void nasluchuj()
        {
            byte[] msg = new byte[sizeof(Int64)];
            Socket zaakceptowany;
            Status nowy = new Status();
            MemoryStream strumien = new MemoryStream();

            try
            {
                klient.Bind(lokalne);
                while (true)
                {
                    klient.Listen(4);
                    zaakceptowany = klient.Accept();
                    zaakceptowany.Receive(msg);
                    strumien.Write(msg, 0, msg.Length);
                    strumien.Seek(0, SeekOrigin.Begin);
                    //strumien = new NetworkStream(zaakceptowany);
                    //strumien.Seek(0, 0);
                    //strumien.Read(msg, 0, msg.Length);
                    nowy = (Status)format.Deserialize(strumien);
                    SetText(nowy.login);
                    strumien.Flush();
                }
            }
            catch(SocketException ex)
            {
                MessageBox.Show("Wystąpił błąd: " + ex);
            }
        }
private void polacz()
        {
            Status nowy = new Status();
            nowy.login = textBox1.Text.ToString();
            nowy.haslo = textBox2.Text.ToString();

            IPHostEntry ip = Dns.GetHostEntry(Dns.GetHostName());
            IPAddress adres = ip.AddressList[0];
            nowy.ip = adres.ToString();
            //nowy.dostepni = null;
            nowy.naglowek = "";
            BinaryFormatter format = new BinaryFormatter();
            MemoryStream strum = new MemoryStream();
            
            try
            {
                sox = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                sox.Connect(serwer);
                strumien = new NetworkStream(sox);
                format.Serialize(strum, nowy);
                sox.Send(strum.ToArray());
                strumien.Flush();
                //byte[] buffor = strumien
                //strumien.Write(buffor, 0, buffor.Length);
                //sox.Send(buffor);
            }
            catch (SocketException ex)
            {
                MessageBox.Show("Wystąpił błąd: " + ex);
            }
        }
0

Wyrzuca Ci OutOfMemoryException bo ustawiłeś rozmiar bufora msg na równy rozmiarowi struktury Int64 czyli 8 bajtów, a Twoje dane które chcesz deserializować mają większy rozmiar. Rób tak: najpierw wysyłaj serwerowi informację o tym jaki rozmiar mają te dane żeby wiedział ile bajtów ma odebrać, a dopiero potem mu je wyślij.

0

Bardzo dziękuje. Pomogło.
Teraz z kolei mam inny problem. Otóż chciałbym, aby cała aplikacja oparta była o komunikację p2p. Nie wymyśliłem (i nie wiem czy takowy istnieje) sposobu na uniknięcie napisania oddzielnego serwera. Ograniczać się on będzie jedynie do przechowywania informacji o klientach zalogowanych i klientach zarejestrowanych (zarejestrowanych będzie trzymał w pliku, wczytywał do listy i sprawdzał, czy osoba chcąca się zalogować jest na tej liście, natomiast w przypadku listy zalogowanych, każda zmiana stanu użytkownika - wylogowanie/logowanie oznacza przesłanie uaktualnionej listy do wszystkich zalogowanych). Pytanie moje dotyczy działania tego serwera. Skoro ma być to komunikacja p2p, to rozumiem, że serwer przyjmuje gościa, dodaje go do listy i się rozłącza tak? Ja rozumiem to tak, że klient chcąc nawiązać konwersacje z innym wysyła do serwera głównego wiadomość (wraz ze swoim ip oraz ip odbiorcy), że to on będzie serwerem. Serwer wysyła do odbiorcy wiadomość z nowym adresem serwera, a odbiorca łączy się z kliento-serwerem. Jeżeli źle kombinuje, to proszę o korektę. Jeszcze raz dziękuje za pomoc. Pozdrawiam

0

Mam kolejny problem i proszę o pomoc. W mojej komunikacji jest aktualnie serwer główny i klienci. Kiedy klient łączy się do serwera otrzymuje od niego Arraylistę z wszystkimi zalogowanymi użytkownikami. Komunikacja od strony serwera działa, bo lista dochodzi i aktualizowany jest listView. Niestety ze strony klienta nie mogę wysłać żadnej wiadomości już po zalogowaniu (czyli pierwsza dochodzi z loginem i haslem). Wydaje mi się, że brakuje gdzieś nieskończonej pętli. Gdy taką próbuję wstawić przy metodzie "wyslij_paczke_serwer" to program się wiesza, a gdy "wkładam ją" w wątek to nic się nie otrzymuję. Proszę o pomoc.
user image

private void polacz()
        {
            Status nowy = new Status();
            nowy.login = textBox1.Text.ToString();
            nowy.haslo = textBox2.Text.ToString();
            nowy.naglowek = "logowanie";
            nowy.msg = "";
            IPAddress o = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0];
            string adres = o.ToString();
            nowy.ip = adres;
            nazwa_klienta = nowy.login;
            ip_klienta = adres;

            try
            {
                sox.Connect(serwer);

                if (sox.Connected)
                    polaczony = true;
                
                wyslij_paczke_serwer(sox, nowy.naglowek, nowy.login, nowy.haslo, nowy.ip, nowy.msg, null, null);

                watek_od_serwera = new Thread(new ThreadStart(delegate { wiadomosci_od_serwera(sox); }));
                watek_od_serwera.IsBackground = true;
                watek_od_serwera.Start();
            }
            catch (SocketException ex)
            {
                AddItem("Wystąpił błąd: " + ex);
            }
        }
private void wyslij_paczke_serwer(Socket receiver, string nag, string name, string pas, string ip, string wiadomosc, ArrayList sox, ArrayList logged)
        {
            Status brand_new = new Status();
            brand_new.naglowek = nag;
            brand_new.login = name;
            brand_new.haslo = pas;
            brand_new.msg = wiadomosc;
            brand_new.sockety = sox;
            brand_new.nazwy = logged;

            try
            {
                if (polaczony)
                {
                    formater = new BinaryFormatter();
                    przesyl = new NetworkStream(receiver);
                    stream = new MemoryStream();
                    formater.Serialize(stream, brand_new);
                    receiver.Send(stream.ToArray());
                    polaczony = true;
                    stream.Flush();
                    przesyl.Flush();
                }
                else
                {
                    AddItem("Nie można połączyć z serwerem");
                }

            }
            catch (SocketException ex)
            {
                AddItem("Wystąpił błąd: " + ex);
            }
        }

user image

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