Paweł Nowosielski

Paweł Nowosielski LinkedIn
(https://www.linkedi
n.com/in/pawelnowosi
elski/)

Temat: Sockety - problem koncepcyjny

Witam Dotnetomaniaków :)

Aplikacja jest serwerem z którą łączy się jeden (i tylko jeden) klient po tcp. Nie wiem czy klient wyślę jedną wiadomość czy może 100-200 w ciągu sekundy, dlatego wydumałem, że będę utrzymywał połączenie tj. klient nawiązuję połączenie i co pewien czas coś wysyła - nie rozłącza się.

Problem jaki mam to wieszanie się połączenia, po jakimś czasie bezczynności - nieregularnie po kilku godzinach - dobie. Klient zaczyna wysyłać, ale serwer nic nie odbiera, sniffer pokazuje, że na porcie jest nasłuch, wiadomości dochodzą na serwer...

Pytanie do bardziej doświadczonych w temacie, czy taki model z utrzymywaniem otwartego socket-a ma sens? Wiem, że połączenie tylko na czas wysłania wiadomości dobrze się sprawdza. Natomiast, w moim przypadku, chciałbym uniknąć częstego łączenia, gdyż nie wiem jak będzie z wydajnością.

Będę bardzo wdzięczny za radę. Gdybym podał za mało informacji, proszę śmiało dopytać :)

Pozdrawiam i z góry dziękuję,
Paweł
Maurycy Mikulski

Maurycy Mikulski programista
C++(MS,QT),C#-MVC,SO
AP,AJAX-REST,SQL

Temat: Sockety - problem koncepcyjny

Utrzymywanie otwartego socket-a ma sens. Szczególnie jeśli nie wiesz kiedy i ile danych zostanie przesłane. Koszt nawiązania połączenia, za każdym razem, może być spory(to oczywiście zależy od częstości takiej operacji).
Napisałem parę takich serwerków i klientów w różnych językach i systemach. Najlepiej wypadło QT. Najgorzej wypadł C#.
W jednym z systemów z przed nastu lat(QNX,win), utrzymywane są połączenia przez wiele miesięcy bez problemów (ostatnio dorabiałem do tego systemu komunikacje w C#).
Osobiście nie spotkałem się z problemem wieszania połączenia. Rozłączanie się zdarza. To trzeba obsłużyć. C# miałem problem z wydajnością odbierania danych z socket-a (przesyłanie 7 tysięcy zmiennych online) potrafiło odczytywać je po czasie, ale nadrabiało gdy był mniejszy ruch (zauważyłem to przypadkowo bo wszystko wyglądało OK , a rozwiązanie było proste).

Połączenie na pewno nadal funkcjonuje. Inaczej przy wysyłaniu klient dostał by wyjątek. Ta więc socket po stronie serwera odbiera dane (i potwierdza ich odbiór). Jeśli tak to problem jest po stronie kodu doczytującego dane w serwerze. Jak to rozwiązałeś?

Maurycy
Paweł Nowosielski

Paweł Nowosielski LinkedIn
(https://www.linkedi
n.com/in/pawelnowosi
elski/)

Temat: Sockety - problem koncepcyjny

Piękne dzięki za odpowiedź, zacząłem wątpić czy to co chcę zrobić jest możliwe :)

Na klienta nie mam żadnego wpływu, więc zakładam, że działa poprawnie. Serwer przy starcie uruchamia w nowym wątku nasłuch na porcie (w dużym skrócie):

TcpListener listener = new TcpListener(...);
listener.Server.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true);
listener.Start();

while (true)
{
TcpClient socket = listener.AcceptTcpClient();
while (socket połączony)
{
socket.GetStream().Read(...);
co zczyta w nowym wątku przetwarza
}
}

Bałem się tego, Że długo otwarte połączenie może się zaciąć gdzieś niskopoziomowo, że z poziomu .NET nie będę o tym wiedział. Podczas zabawy z socketami nauczyłem się, że dokumentacja delikatnie mówiąc mija się z prawdą (chociażby działanie metody Read), wszystko co do tej pory się udało wyszło z debuggowania i oczywiście pomocy na forum :)
Druga obawa to, że GC wytnie wątek nasłuchujący - uruchamiam go z IsBackground = true i mam nadzieję w ten sposób go zabezpieczyć... :)

konto usunięte

Temat: Sockety - problem koncepcyjny

Możesz do tego spokojnie użyć Windows Process Activation:

http://technet.microsoft.com/en-us/library/cc735229(WS...
http://msdn.microsoft.com/en-us/library/ms734677.aspx

http://www.google.pl/search?q=Windows+Process+Activati...

Wtedy masz z głowy martwienie się o otwarte połączenia czy inne rzeczy - tym się martwi IIS i WIndows.

Wadą tego jest to, że musisz się podporządkować zarówno po stronie klienta jak i serwera do tego protokołu.Karim Agha edytował(a) ten post dnia 18.03.10 o godzinie 16:15
Paweł Nowosielski

Paweł Nowosielski LinkedIn
(https://www.linkedi
n.com/in/pawelnowosi
elski/)

Temat: Sockety - problem koncepcyjny

Nie napisałem... .NET 2.0 nie ma WCF i WAS :(
Nie ma szans, żeby zmienić klienta - to jakaś czarna skrzynka po drugiej stronie kabla :)

... ale dziękuję za wypowiedź, może się przydać innym razem :)Paweł Nowosielski edytował(a) ten post dnia 18.03.10 o godzinie 16:22

konto usunięte

Temat: Sockety - problem koncepcyjny

Aaaa.. ;-)
Maurycy Mikulski

Maurycy Mikulski programista
C++(MS,QT),C#-MVC,SO
AP,AJAX-REST,SQL

Temat: Sockety - problem koncepcyjny

Założyłem błędnie, że masz wpływ na klienta.

while (socket połączony)
{
socket.GetStream().Read(...);
co zczyta w nowym wątku przetwarza
}

Czy to oznacza ,że przekazujesz obiekt socket do innego wątku , gdzie dokonujesz czytania danych?
Nadal trochę mało informacji.
Jeśli nie zamykasz połączenia należy założyć, że będzie ich więcej niż jedno, nawet jeśli zakładasz, że ma być jedno. Najlepiej zrobić listę przechowującą obiekty wątków czytających z socjet-a (musisz też przeglądać co pewien czas tę listę i usuwać zamknięte połączenia.)
Rozumiem, że po rozłączeniu klient jak ma dane próbuje ponowić połączenie.
Jest jeden problem. Tak naprawdę nie wiesz czy połączenie nadal jest, czy doszło do jego zerwania. Dopiero gdy zaczniesz pisać do socjet-a, jeśli połączenie jest nieaktualne dojdzie do wywołania wyjątku i ustawienie prawidłowych statusów połączenia.
Ja rozwiązałem ten problem w taki sposób, że serwer wysyła co pewien czas informacje do klienta, która jest przez niego ignorowana. W ten sposób mam pewność wykrycia rozłączenia po stronie serwera.
Paweł Nowosielski

Paweł Nowosielski LinkedIn
(https://www.linkedi
n.com/in/pawelnowosi
elski/)

Temat: Sockety - problem koncepcyjny

Spróbuję podać więcej informacji:
- dokładnie jeden, zawsze ten sam klient łączy się z serwerem
- serwer nasłuchuje i odczytuje wiadomosci w jednym tym samym wątku, dwie pętle while - zewnętrzna nasłuch, wewnętrzna zczytywanie wiadomości, oczywiście obsługuje wyjątki, bo jak piszesz jedyny sposób by dowiedzieć się o status połaczenia to próba zapisu / odczytu
- na początku każdej wiadomości idzie jej długość więć zczytuje tyle bajtów ile ma wiadomość i samą tablice byte[] przekazuje delegatem, asynchronicznie do dalszej obróbki
- klient potrafi sam się podłączyć jeśli nastąpi zerwanie połączenia, więc powinienem go złapać w następnym obrocie zewnętrznego while-a
- pamiętam tylko jeden (ostatnio podłączony) socket (a dokładniej TcpClient) i za jego pomocą jest asynchroniczna komunikacja w drugą stronę czyli do klienta, jest lock () aby wątki przetwarzające wiadomości i odpowiadające na nie, nie wpisywały w strumień jednocześnie.

To jest jeszcze pewne uproszczenie, bo jeszcze sporo sie dzieje pomiędzy odebraniem wiadomości a odpowiedzią. System przechodzi stress testy z spreparowanym klientem, który wysyłał setki wiadomości i tu wszystko działało. W tym momencie jest problem jeśli połączenie jest utrzymywane przez dłuższy czas bez wymiany wiadomości. Pomyślę o wysyłaniu jakiejś ignorowanej przez klienta wiadomości by wykryć rozłączenie.

Na co jeszcze powinienem uważać?
Dziękuję.

konto usunięte

Temat: Sockety - problem koncepcyjny

Paweł Nowosielski:
Spróbuję podać więcej informacji:
- dokładnie jeden, zawsze ten sam klient łączy się z serwerem
- serwer nasłuchuje i odczytuje wiadomosci w jednym tym samym wątku, dwie pętle while - zewnętrzna nasłuch, wewnętrzna zczytywanie wiadomości, oczywiście obsługuje wyjątki,

Jeśli to jest zawsze JEDEN klient to po co komplikować z wątkami? I tak w danej jednosce czasu zawsze będziesz obsługiwał tylko jednego klienta?

W tym momencie jest problem jeśli połączenie jest utrzymywane przez dłuższy czas bez wymiany wiadomości.

Jesteś pewien, że nie zgubiłeś nigdzie żadnego niezłapanego wyjątku? Nie ma żadnego ograniczenia jak długo serwer siedzi na gniazdku i nasłuchuje bezczynnie.

Zastanawia mnie też KeepAlive - ustawiasz tę opcję i to ona może powodować problem. KeepAlive polega na wysyłaniu prztyczków w nos i jeśli po jakimś czasie (ilości prób) nie zostanie ponownie odebrany jakiś pakiet to połączenie jest terminowane.

Zerknij w rejestrach:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters

i sprawdź czy wartości tam ustawione, dot. keepalive'a nie zgrywają się z charakterystyką problemów zerwanego połączenia w Twojej aplikacji.

Jeszcze jedna rzecz: niektóre karty sieciowe długotrwały IDLE na otwartym gnieździe traktują jako zawieszkę lub martwe połączenie i same takie gniazdo zamykają.Sergiusz B. edytował(a) ten post dnia 19.03.10 o godzinie 16:38
Tomasz Leszczyński

Tomasz Leszczyński Sales Engineer,
Andra Sp. z o.o.

Temat: Sockety - problem koncepcyjny

A może by tak zainteresować się UDP?

Następna dyskusja:

problem z serializacja cdata




Wyślij zaproszenie do