2010-06-29 9 views
7

Mamy prostą architekturę serwera klienckiego między naszym urządzeniem mobilnym a naszym serwerem, zarówno napisaną w Javie. Niezwykle prosta implementacja ServerSocket i Socket. Jednak jednym z problemów jest to, że gdy klient nagle kończy pracę (bez zamykania gniazda), serwer nie wie, że jest odłączony. Ponadto serwer może kontynuować pisanie do tego gniazda bez żadnych wyjątków. Czemu?Gniazdo Java nie rzuca wyjątków na martwym gnieździe?

Zgodnie z dokumentacją gniazda Java powinny generować wyjątki, jeśli spróbujesz napisać do gniazda, które nie jest dostępne na drugim końcu!

Odpowiedz

0

Komunikacja TCP/IP może być bardzo dziwna. Protokół TCP będzie próbował ponownie przez chwilę na dolnych warstwach stosu, nawet jeśli nie będzie wiedział, że coś się stało.

W pełni oczekiwałbym, że po pewnym czasie (od 30 sekund do kilku minut) powinien pojawić się błąd, ale nie testowałem tego. Właśnie wychodzę z tego, jak działają aplikacje TCP.

Być może uda się dokręcić specyfikacje TCP (ponowienie, limit czasu, itp.), Ale znowu nie pomieszano z nim zbyt wiele.

Możliwe też, że całkowicie się mylę, a implementacja Java, której używasz, jest po prostu niestabilna.

2

Połączenie zostanie ostatecznie przekroczone przez czas retransmisji (RTO). Jednak RTO jest obliczana na podstawie skomplikowanego algorytmu opartego na opóźnienia w sieci (RTT), zobacz ten RFC,

http://www.ietf.org/rfc/rfc2988.txt

Więc w sieci komórkowej, może to być minuty. Poczekaj 10 minut, aby sprawdzić, czy możesz uzyskać limit czasu.

Rozwiązaniem tego problemu jest dodanie rytmu serca do własnego protokołu aplikacji i zerwanie połączenia, gdy nie otrzymasz potwierdzenia ACK dla pulsu.

1

Kluczowe słowo tutaj: (without closing the socket properly).

gniazda powinny być zawsze nabyte i unieszkodliwiane w ten sposób:

final Socket socket = ...; // connect code 

try 
{ 
    use(socket); // use socket 
} 
finally 
{ 
    socket.close(); // dispose 
} 

Nawet z tym środki ostrożności należy określić limity czasu aplikacji, specyficznych dla danego protokołu.

Moje doświadczenie pokazało, że niestety nie można niezawodnie korzystać z żadnej funkcji limitu czasu gniazda (np. Nie ma limitu czasu na operacje zapisu, a nawet operacje odczytu mogą czasami trwać wiecznie).

Dlatego potrzebny jest wątek watchdog, który wymusza limity czasu aplikacji i unieszkodliwia gniazda, które przez jakiś czas nie reagowały.

Jednym z wygodnych sposobów robienia tego jest inicjowanie Socket i ServerSocket za pośrednictwem odpowiednich kanałów w java.nio. Główną zaletą takich gniazd jest to, że są one Przerywalne, w ten sposób można po prostu przerwać wątek, który wykonuje protokół gniazda i upewnić się, że gniazdo jest odpowiednio ułożone.

Należy zauważyć, że należy wymuszać limity czasu aplikacji po obu stronach, ponieważ jest to tylko kwestia czasu i nieszczęścia, kiedy mogą wystąpić niewrażliwe gniazda.

0

Aby odpowiedzieć na pierwszą część pytania (o nieświadomości, że klient nagle przerwał połączenie), w protokole TCP nie można ustalić, czy połączenie zostało zakończone, dopóki nie spróbujesz go użyć.

Pojęcie guaranteed delivery in TCP jest dość subtelne: dostawa nie jest faktycznie gwarantowana aplikacji na drugim końcu (zależy to od tego, co naprawdę gwarantowane znaczy). Section 2.6 of RFC 793 (TCP) podaje więcej szczegółów na ten temat. This thread on the Restlet-discuss list i this thread on the Linux kernel list może również zainteresować.

Dla drugiej części (nie wykrywając, kiedy piszesz do tego gniazda), jest to prawdopodobnie kwestia bufora i limitu czasu (jak już sugerowali inni).

+0

Próbowałem już użyć go, pisząc do gniazda, a nawet wtedy nie wiem, czy klient się rozłączył. – erotsppa

0

Mam do czynienia z tym samym problemem. Myślę, że po zarejestrowaniu gniazda za pomocą selektora nie rzuca żadnego wyjątku. Czy używasz selektora z gniazdem?

Powiązane problemy