Serwer UDP

0

Witam

Robię sobie programik, który komunikuje się po udp. Czyli tworzę serwer UDP i czekam aż coś przyjdzie na port. Znalazłem rozwiązanie, które pozwala na obsługę jednego klienta w danym czasie, ale potrzebuję obsłużyć w jednym czasie wielu klientów i tutaj mam już problem. Nakombinowałem się sporo, ale ciągle mi nie wychodzi.

Kod metody, która nasłuchuje:

private void Sluchaj()
        {
            try
            {

                  udpState = new UdpState();//Klasa która przechowuje obiekty: UdpClient, IPEndPoint i tablicę bajtów odebranych danych

                  udpState.IPEndPoint = new IPEndPoint(IPAddress.Any, port); 

                   udpState.UdpClient = new UdpClient(udpState.IPEndPoint);

                        while (listening && (udpState.UdpClient.Client != null && udpState.UdpClient.Available <= 0))//czekam kiedy na porcie pojawią się jakieś dane, w przeciwnym razie od razu wchodzi do metody OnClientConnect
                        {
                            Thread.Sleep(15);
                        }

                        udpState.UdpClient.BeginReceive(new AsyncCallback(OnClientConnect), udpState);

                    }

            }
            catch (Exception se)
            {

            }

        }

Metoda OnClientConnect:

private void OnClientConnect(IAsyncResult ar)
        {
            try
            {
                UdpState udpStateTMP = (UdpState)ar.AsyncState;

                udpStateTMP.buffer = udpStateTMP.UdpClient.EndReceive(ar, ref udpStateTMP.IPEndPoint);

                udpStateTMP.UdpClient.Connect(udpStateTMP.IPEndPoint);

                ThreadStart threadStart = delegate { new UDPKlient(udpStateTMP); };
                Thread watek = new Thread(threadStart);
                watek.Start();

            }
            catch (Exception ex)
            {

            }
            finally
            {
                udpState = null;

                if (listening)
                    Sluchaj();
            }
        }

Więc reasumując, chciałbym dla każdego zgłoszenia stworzyć sobie osobną klasę UDPKlient, która będzie realizowała połączenie z konkretnym klientem który się zgłosił.
Trochę się w tym wszystkim pomotałem i potrzebuję pomocy :(

Z góry dzięki :)

0

Hmm... Proponuję zacząć od lektury: http://pl.wikipedia.org/wiki/UDP

Protokół UDP jest bezpołączeniowy, więc tworzenie nowego wątku i nowego socketa dla każdego przychodzącego pakietu spowoduje po jakimś czasie spore problemy z wydajnością programu (systemu pewnie również). Do tego nie używasz metody Close przez co nieużywane zasoby nie mogą być zwolnione.

Zamiast bawić się wielowątkowością utwórz w głównym wątku obiekt UdpClient i wywołaj BeginReceive podając w argumencie funkcję, która zajmie się wymianą danych. W tej funkcji wywołaj metodę EndReceive, obsłuż odebrane dane, ewentualnie prześlij dane do klienta i ponownie wywołaj BeginReceive podając w argumencie tą samą funkcję.
Nie jest to idealna metoda, jest jedynie banalnie prosta. Jej wadą jest czas między odebraniem danych, a ponownym wywołaniem BeginReceive. Jeśli obróbka danych będzie trwała długo, to będą duże opóźnienia, bufory będą się zapychały i będzie mało fajnie. Najlepiej byłoby użyć kolejkowania odebranych pakietów i obróbkę danych przenieść do innego wątku lub ewentualnie tworzyć nowy wątek dla każdego odebranego pakietu (co przy dłuższej obróbce danych może sprawić, że będziesz miał bardzo dużo wątków, chyba, że dasz jakieś ograniczenie). Ale na dobry początek wystarczy ta prosta metoda.

0

No właśnie problem w tym że sprowadziłeś to do synchronicznej wymiany danych: jeden klient w jednym czasie. A chodzi o to że mam wielu klientów którzy mogą się łączyć w tej samej chwili i do tego nie z każdym klientem komunikacja wygląda tak samo więc muszę tworzyć dla każdego klienta osobną instancję klasy UDPKlient żeby pakiety od jednego klienta rozpatrywać w jednym miejscu i w jednym miejscu odpowiednio na nie reagować, no i właśnie to jest cały problem :(

0

To udp, tu nie ma żadneg łączenia. Pakiet udp poszedl, serwer go odebrał i tyle. Zrób to na socketach - serwer powinien oczekiwać na pakiety udp i po otrzymaniu pakietu tworzyć nowy wątek, w którym żądanie będzie obsłużone nie blokując nasłuchiwania na komunikaty od kolejnych klientów. Sam socket jest tylko jeden i cały czas czeka na komunikaty.

Zacznij od tego: http://msdn.microsoft.com/en-[...]ystem.net.sockets.socket.aspx

0

Piotr1278, to jest protokół UDP. Tu nie ma połączeń. Są tylko pakiety z danymi odbieranymi od różnych klientów i wysyłanymi do różnych klientów, które docierają w pełni synchronicznie. Możesz tworzyć oddzielny wątek dla każdego klienta rozpoznając go na podstawie adresu oraz portu z którego dociera pakiet. Problem jest w tym, że klient może w pewnym momencie zniknąć i nie będziesz miał pojęcia o tym, że go już nie ma. A wątki "niepołączonych" klientów przydałoby się usuwać. Oczywiście można zaimplementować jakiś pingujący pakiet, na który klient powinien odpowiadać i jeśli klient nie odpowiedział w ciągu x sekund y razy, to wątek danego klienta zostaje usunięty. Ale to bardzo skomplikuje program. W przypadku UDP masz również tylko jeden socket, który będzie oczekiwał na przychodzące dane, bo nie może kilka socketów słuchać na jednym porcie. Możesz po odebraniu pakietu przekierować klienta na inny port i utworzyć nowy socket, który będzie nasłuchiwał na tym porcie, ale to znowu komplikuje bardziej program.

Po tym co chcesz uzyskać, ewidentnie protokół TCP będzie lepszy, chyba że musi to być koniecznie protokół UDP i zamierzasz napisać spory program...

Jeśli już ma to działać na UDP, to ja bym utworzył oddzielną klasę w której przechowywałbym informacje o danym kliencie i dla każdego nowego klienta tworzył nową instancję i umieszczał ją w kolekcji. Za każdym razem gdy będzie ten klient się komunikował, program będzie pobierał informacje o kliencie z tej kolekcji, z nich korzystał i aktualizował je. Dodatkowo przydałoby się zaimplementować mechanizm, który będzie z listy usuwał klientów, którzy przez określony czas nie komunikowali się z serwerem. Tyle, że próba pewnego symulowania połączeń na protokole UDP jest raczej nienajlepszym pomysłem.

0

Dziękuję za obszerne wyjaśnienia :) Chodziło mi o to czy będę w stanie powiązać pakiety z konkretnym klientem czy też, jak mi to wyjaśniliście, pakiety przychodzą na tylko i wyłącznie gniazdo serwera i muszę je obrobić w klasie serwera. Chyba że rozpoznawał bym pakiety po adresie, ale to już jest inna bajka. Porównując do TCP: serwer nasłuchuje i w momencie nawiązania połączenia jest tworzony nowy socket i nie ma problemu, natomiast w UDP tego nie ma i to jest różnica, o która mi chodziło :) Jest jeden socket nasłuchujący i koniec. Rozdzielanie danych, które przychodzą, pomiędzy obiektami trzeba zrobić we własnym zakresie.

Jeżeli nadal źle to rozumiem to proszę o korektę. W przeciwnym wypadku temat uważam za zamknięty. Dziękuję za pomoc.

0

Dobrze zrozumiałeś.

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