C#, gniazda, network programming i p2p

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

Kopiuj
 [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

Kopiuj
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

Kopiuj
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 :(

Kopiuj
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);
            }
        }
Kopiuj
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);
            }
        }
SI
  • Rejestracja:ponad 15 lat
  • Ostatnio:około 3 lata
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

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

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)