Witam. piszę program, który ma za zadanie sterować tablicami LED. Część kodu wykorzystałem od producenta tablic (miałem źródła) - były tam klasy sterujące i klasa TelNet Connection, która miała za zadanie nawiązywać połączenie z tablicą. Domyślnie program obsługuje jedną tablicę, a chciałbym, by wszystkie dało się wysterować za jednym razem. Obecnie wygląda to tak, że w pętli przelatuję przez IP wszystkich tablic, loguję się, wchodzę w tryb pasywny (FTP), przesyłam dane i się wylogowuję. Jednak po pewnym czasie tablice się wieszają. Producent poradził, bym utrzymywał cały czas połączenie z tablicami, sęk w tym, że nie bardzo wiem jak to zrobić. Myślałem, żeby po dodaniu IP przejść przez wszystkie dodane i potworzyć połączenia. Jednak nie mam pomysłu jak to wykonać i liczę na Wasze podpowiedzi.
Rozwiązanie - wątki.
Z tego co widzę klasa TelnetConnection opakowuje po prostu Socket, więc widzę dwie opcje:
-
Archaiczną, jak wyżej. Każdy socket dostaje swój wątek.
-
Polegającą na multipleksowaniu gniazda. Masz jeden wątek który odwiedza tablicę kanałów. Jeśli na którymś kanale coś się pojawi, to wątek wykonuje pracę polegającą na odczytaniu/wysłaniu danych i jakimś obsłużeniu ich. Nie znam niestety C# bardziej niż mocno podstawowy. W Java masz to już gotowe w klasie SocketChannel. Sądzę, że C#, też powinien mieć coś podobnego - może ktoś inny wskaże konkretną klasę.
Na jakiej podstawie podjąć decyzję, którą opcję wybrać?
Na pewno wybrać 2), jak musisz otworzyć bardzo dużo połączeń, typu 1000. Inaczej system będzie 99% czasu marnował na przełączenie się miedzy wątkami.
Opcja 1) może być sensowna, jeżeli masz zadania, które bardzo długo trzeba odczytywać (duży rozmiar przesyłanych danych) oraz długa obróbka/obsługa danych, które przyszły. Innymi słowy ten jeden wątek by się na długo zablokował w związku z dużym czasem całościowego przetwarzania danych (transmisja + przetwarzanie właściwe).
jest to komunikacja jednostronna, niestety tablice nie zwracają mi błędów czy coś w tym stylu. Nie potrafię sobie wyobrazić jak do wątku dodać jeden socket, skoro obecnie muszę się zalogować na każdą z tablic oddzielnie. Może jakiś pseudokod? Po prostu nie potrafię sobie tego wyobrazić jak zapisać te wątki
Ciekawe, że pomimo tego, że było wylogowanie tablice się wieszają. Rozumiem, że mowa jest tu o sytuacji, gdy po pewnym czasie nie można się już połączyć z tablicą. Bo teraz pytaniem jest czy faktycznie wiesza się tablica, czy połączenie. W jaki sposób wówczas przywracasz obsługę tablic? Resetujesz tablice czy program/połączenie?
Jeśli producent podpowiedział utrzymywanie połączenia, spróbuje dodać do obsługi Socketów w klasie TelnetConnection, utrzymywanie połączenia wg np. tych linków:
http://stackoverflow.com/questions/6501461/c-sharp-net-socket-keep-alive-time
https://msdn.microsoft.com/pl-pl/library/e160993d(v=vs.110).aspx
Na tablice wysyłam 1-bitowe bitmapy w odstępie 5-10 sekund. Działa normalnie jakiś czas. Testuję to na 2 tablicach teraz. Program działa tak, że najpierw wysyła na jedną tablicę, rozłącza się i wysyła na drugą. Jeśli któraś z tablic się zawiesi, druga działa normalnie do czasu, kiedy sama się nie zawiesi. Na zawieszonej tablicy pojawiają się artefakty (czyli kilka losowych diod LED się zapala oprócz tych, które są w bitmapie. Po zawieszeniu program sterujący działający na serwerze wysyła dane dalej bez żadnego błędu. Co ciekawe, jak tablica jest zawieszona mogę jej swoim programem wysłać tekst, który zawieszona tablica wyświetla. Przywrócenie “trybu graficznego” nie działa - tablica dalej jest zawieszona. W takiej sytuacji trzeba tablicę odłączyć z prądu na moment. Po restarcie wyświetla już normalnie - program ją wychwytuje i wysyła dane.
@Czajo Przejrzałem udostępniony kod. Widzę tam, że logujesz się za pomocą klasy TelnetConnection, która de facto jest opakowaniem TcpClient. Później zaś tworzysz nowe połączenie w metodzie SendStreamPasiveMode(). Metody EnterPassiveMode() i SendGraphic() używają zaś połączenia z TelnetConnection (czyli z pierwszego TcpClienta). Czyli masz dwa połączenia, przy czym w SendStreamPasiveMode() jest ono zamykane po wyjściu zaś w TelnetConnection nie zamykasz go. Wg mnie powinieneś używać konsekwentnie jednego połączenia w każdej z metod (nie tworzyć nowego w SendStreamPasiveMode). Skoro producent zaleca utrzymywanie połączenie to otwarte raz połączenie do tablicy w TelnetConnection powinieneś dodatkowo oznaczyć jako KeepAlive, chyba że zdecydujesz się mimo wszystko na zamykanie połączenia po wysłaniu. Na pewno na początku zmień metodę SendStreamPasiveMode(), aby używała połączenia z TelnetConnection.
akurat te metody udostępniał producent.
Wiem już jak stworzyć wątki dla każdej z tablic, ale jak zrobić wywołanie danej metody (SendGraphic) już na istniejących wątkach?