Czat Wieloosobowy

0

Witam, napisałem w c# czat ale tylko 1:1 Server -> client na anynchronicznych TcpClient.

Chciałbym rozszerzyć program o możliwość konwersacji z wieloma osobami. Moja logika jest taka:

  1. Client wysyla wiadomosc do serwera
  2. Server odbiera i wysyła foreach każdego klienta tą wiadomosc ( rowniez do tego co wysłał, dubluje ale ułatwia to troche życie)
  3. TextBoxKażdegoKlienta.add(wiadomosc);

Otwieram aplikacje:

  1. Server start
  2. Client łączy się
  3. Wysyła wiadomosc, serwer zwraca
  4. Tylko jeden klient moze wysyłac wiadomosc do pozostałych, od innych wiadomosc nie dochodzi.foo

W następnym wysyłaniu z różnych chatów Client 1 / 2 wiadomości dochodzą ale nie od razu i nie w takich kolejnościach.

kody:
Server: http://pastebin.com/mBgEA8za
Clienci: http://pastebin.com/bEd5PqPv

Opis:
Wątki work 1-3
wątek 1 - nasłuchiwanie połączenia ( w whilu)
wątek 2 - wysyłanie
wątek 3 - *** TYLKO SERWER *** Wyszukiwanie nowych klientów.
kod:

private void backgroundWorker3_DoWork(object sender, DoWorkEventArgs e)
        {
            TcpListener listener = new TcpListener(IPAddress.Any, 13000);
            //listaTcpListener.Add(new TcpListener(IPAddress.Any, 13000)); czy wystarczy 1 listener?
            bool NieMaZadnegoKlienta = true;
            int licznikClientow = 0;
            while (true)
            {
                listener.Start(); // nasluchujemy
                listaClientow.Add(new TcpClient()); // dodajemy nowego
                listaClientow[licznikClientow] = listener.AcceptTcpClient(); //przypisujemy 
                listaSTR.Add(new StreamReader(  listaClientow[licznikClientow].GetStream() ) );  // do czytania
                listaSTW.Add(new StreamWriter(  listaClientow[licznikClientow].GetStream() ) );   // do wysylania wiadomosci
                listaSTW[licznikClientow].AutoFlush = true; //czysci bufor
                if(listaClientow[0].Connected && NieMaZadnegoKlienta) // start watku nasluchiwania przez serwer
                {
                    NieMaZadnegoKlienta = false; 
                    worker1.RunWorkerAsync();  // ten nasluchuje
                    worker2.WorkerSupportsCancellation = true; //ten wysla
                }
                licznikClientow++;
            }
        } 

Do tego stworzyłem 3 listy, chyba TcpListerner ma byc tylko jeden? wiec nie tworzyłem listy

private List<TcpClient> listaClientow = new List<TcpClient>();
private List<StreamReader> listaSTR = new List<StreamReader>();
private List<StreamWriter> listaSTW = new List<StreamWriter>();

Bardzo proszę o pomoc !

1

client na anynchronicznych TcpClient

No tak średnio to asynchroniczne, jeśli korzystasz jedynie z synchronicznych metod TcpListenera i TcpClienta a całość opakowałeś w BackgroudnWorkera.

Po co w ogóle w klasie serwera ten licznik klientów, listy streamreaderów i writerów? Przecież to wszystko możesz załatwić jedną listą List<TcpClient> connectedClients ?

Dlaczego w klasie klienta masz jakieś metody używające TcpListenera?

0

Dziękuję za odpowiedź.

No tak średnio to asynchroniczne, jeśli korzystasz jedynie z synchronicznych metod TcpListenera i TcpClienta a całość opakowałeś w BackgroudnWorkera.

Nie zastanawiałem się nad tym. Tak po prostu działa i zostawiłem.

Po co w ogóle w klasie serwera ten licznik klientów, listy streamreaderów i writerów?
Przecież to wszystko możesz załatwić jedną listą List<TcpClient> connectedClients ?

Hmmm.... Brzmi logicznie, ale nie wiedziałem że tak można postąpić. Z edytuje za chwilkę to.
Aczkolwiek do:

listener.Start(); // nasluchujemy
listaClientow.Add(new TcpClient()); // dodajemy nowego
listaClientow[licznikClientow] = listener.AcceptTcpClient(); //przypisujemy  

Jest wymagany jakis licznik, chyba zeby jakoś pisać: listaClientow.OstatniElement = listener.AcceptTcp...

Gdy już rozpocząłem edycje... W kwestii STR/STW:

listaSTR.Add(new StreamReader(  listaClientow[licznikClientow].GetStream() ) );  // dla listy
STR(Client.GetStream() ) ; // moje rozwiazanie dla poprzedniego czatu 1 x client  + server
STR(listaClientow.) 

// Jeżeli jeden STR miałby być to jak to zapisac? Visual nic nie znajduje sensownego po kropce z tagiem: "stream" :(

Dlaczego w klasie klienta masz jakieś metody używające TcpListenera?

Odpowiedź jest tutaj taka, iż wcześniej miałem jeden plik do bycia zarówno serverem jak i klientem. Teraz rozbiłem na dwa programy, ale nie usunąłem starej zawartości. : ))

0

Odkryłem coś; nie wiem czy Amerykę czy po prostu nie wiedziałem podstawowej sprawy.

Kombinowałem z kodem, próbując wycisnąć z niego nowe sugestie

                    received = "";
                    for (int i = 0; i < licznikClientow; i++)
                    {
                        received += listaSTR[i].ReadLine();
                    }
                    if(received!="")
                    {
                        this.textBox.Dispatcher.Invoke(DispatcherPriority.Normal, 
                        (ThreadStart)delegate () { textBox.AppendText("->> " + received + "\n"); });
                        worker2.RunWorkerAsync();
                    } 

Po uruchomieniu programu:

  1. Server start
  2. Client1 connect
  3. Client2 connect
  4. Client1 wysyła: "a"
    .. nic sie nie dzieje
  5. Client1 wysyła: "b"
    ... dalej nic sie nie dzieje
  6. Client2 wysyła: "c"
  7. Pojwia sie wiadomosc u Client1 i Client2 "abc"

Zatem receive = StreamReader czeka aż coś dostanie. Zatem każdy klient musi mieć osobny wątek? Gdyż w tym miejscu się blokuje. Da sie to jakoś obejść?foo

Serdecznie pozdrawiam

0

Proszę zamknąć temat : ))
1 wątek = 1 client załatwiło sprawę pięknie teraz śmiga :D

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