c# wysyłanie wiadomości przez serwer do kilku klientów

0

Jak wysłać z serwera wiadomość do kilku klientów? Robię taki "czat" i klienci widzą tylko to, co sami napiszą i nie wiem co zrobić, żeby widzieli wiadomości także od innych klientów. Każdy klient to nowy wątek i kompletnie nie mam pojęcia jak to zrobić :/

0

Po pierwsze - każdy klient na serwerze powinien być reprezentowany przez klasę, która przechowuje wątek i posiada zdarzenia, które będzie on zgłaszał - jak na przykład właśnie wysyłanie wiadomości, oraz będzie przechowywał jego wątek. Dodatkowo każdy z tych klientów powinien być przechowywany w tablicy.

To po krótce o strukturze programu. Aby wykonać zadanie z wysyłaniem wiadomości, powinniśmy stworzyć metodę, która będzie wywoływana przez wszystkich klientów po otrzymaniu wiadomości, i w tej metodzie serwer będzie wysyłał tą własnie wiadomość do każdego użytkownika z listy, o której napisałem poprzednio.

1

@underTaker Trochę namieszałeś. Sposób 1 klient = 1 wątek jest dobry na początek, ale potem nie wyobrażam sobie 1000 wątków dla 1000 klientów. Wg mnie powinno się obsługiwać klientów po kolei i lepiej żeby klienci byli na liście, a nie w tablicy, bo tablica jest stała, a poza tym lista jest wygodniejsza.

Co do całego procesu czatowania, to klient przesyła wiadomość z listą odbiorców do serwera, a serwer odczytuje tychże odbiorców i samą wiadomość. Następnie wysyła do odbiorców (jeżeli są online) wiadomość razem z nadawcą. Schemat:

  • KLIENT->SERWER [odbiorca1, odbiorca2...], [wiadomość]
  • SERWER->KLIENT1 [nadawca], [wiadomość]
  • SERWER->KLIENT2 [nadawca], [wiadomość]
    ...

Aby serwer wiedział, że to już koniec odbiorców możesz tuż po ostatnim odbiorcy wstawić jakiś ciąg np. <EOF> i czytać aż do napotkania tego ciągu. Zależy to od tego jaką metodą czytasz dane, dla mnie najwygodniejsze są BinaryReader i BinaryWriter, przy wysyłaniu od razu wstawia długość, a reader pierw odczytuje tę długość i wie ile ma zczytać. Wtedy każde użycie readera to jeden odbiorca, a na końcu otrzymasz <EOF> o ile w writerze go wstawisz :)

Acha, aby serwer wiedział, że akurat klient chce wysłać wiadomość, a nie np. spytać o status któregoś użytkownika, powinieneś mieć zbiór "komend" dla serwera i dla klienta.

Teraz przykład oparty na kodzie:

// SERWER:
List<Client> clients = new List<Client>(); // Client to klasa obsługująca klienta

// gdzieś musisz pobrać z obiektu TcpClient właściwość Available, która mówi czy w strumieniu są jakieś dane do odebrania, u mnie przykładowo jest to w klasie Client
foreach (Client client in clients)
{
    if (client.Available)
    {
        byte cmd = client.Reader.ReadByte();
        if (cmd == /* tu wstawiasz tę "komendę" odpowiadającą za wys. wiadomości */)
        {
            List<string> recipients = new List<string>();
            string data = string.Empty;
            while (data != "<EOF>")
            {
                data = client.Reader.ReadString();
                recipients.Add(data);
            }
            string msg = client.Reader.ReadString();

            // sprawdzasz, którzy klienci są online
 
            // i wysyłasz do tych co są online
            foreach (...)
            {
                client.Writer.Write(/* komenda mówiąca o nadchodzącej wiadomości */);
                client.Writer.Write(/* nadawca */);
                client.Writer.Write(msg);
            }
        }
    }
}

Coś na wzór tego.

Oczywiście właściwości Reader i Writer klasy Client to właśnie BinaryReader i BinaryWriter.

0

Miałem na myśli własnie listę :)

Też się zastanawiałem nad sposobem z jednym wątkiem, jednak tutaj mi się nasuwa pytanie - czy wydajność takiego rozwiązania jest dobra? Nawet przy przysyłaniu przez kilku klientów długich wiadomości?

0

To musiałyby by na prawdę bardzo długie wiadomości i bardzo dużo klientów, żeby to miało zaniżyć mocno wydajność, ew. można zrobić kilka wątków i z jednej listy obsługiwać klientów w kilku wątkach, np. 1 wątek - klienci od 1. do 100., 2. od 101. do 200. itd.

0

Hmm, dobrze wiedzieć na przyszłość.

0

Po pierwsze zbyt duża ilość wątków odbije się negatywnie na wydajności, gdyż dłużej będzie trwało samo przełączenie się między wątkami, niż jego praca.

Wg mnie do do obsługi komunikatów najlepsza będzie kolejka, ktoś wysyła do serwera, dodaje się do kolejki (thead safe), zaś np 10 wątków rozsyła wiadomość, jeśli wyśle jedną, pobiera kolejną i tak w kółko.

0

Ja sugeruję skompilować w release i uruchomić bez debugera taki kod (autorstwa zapewne apl z CodeGuru):

using System;
using System.Threading;

class Program
{
    class ThreadContainer
    {
        public Thread CurrentThread;
        public ThreadContainer NextContainer;
    }

    static void Main()
    {
        int threadCount = 0;
        ThreadContainer container = null;
        Console.WriteLine("Creating threads...");
        try
        {
            while (true)
            {
                var thread = new Thread(
                   delegate()
                   {
                       Thread.Sleep(Timeout.Infinite);
                   }
                );
                thread.IsBackground = true;
                thread.Start();
                threadCount++;
                container = new ThreadContainer
                {
                    CurrentThread = thread,
                    NextContainer = container
                };
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("Operation aborted with " + e.GetType().Name + " exception.");
            Console.WriteLine("Created " + threadCount + " threads.");
            Console.ReadLine();
        }
    }
}

I wyciągnąć wnioski co do tworzenia wątków w nieskończoność.

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