2012-10-25 15 views
9

Mam bardzo dziwne zachowanie podczas pisania do gniazda. W moim telefonie klienta używam gniazdo, które jest zainicjowany w następujący sposób:OutputStream.write() się powiodło, ale dane nie zostały dostarczone

private void initSocket() 
{ 
    socket = new Socket(); 
    socket.connect(new InetSocketAddress(host, port)); 

    os = new DataOutputStream(socket.getOutputStream()); 
    is = new DataInputStream(socket.getInputStream()); 
} 

następnie okresowo (co 60 sekund) I czytać i pisać jakieś dane do tego gniazda (kod tutaj jest trochę uproszczona) :

if(!isSocketInitialized()) 
{ 
    initSocket(); 
} 

byte[] msg = getMessage(); 

os.write(msg); 
os.flush(); 

int bytesAvailable = is.available(); 
if(bytesAvailable>0) 
{ 
    byte[] inputBuffer = new byte[bytesAvailable]; 

    int numRead = is.read(inputBuffer, 0, bytesAvailable); 
    processServerReply(inputBuffer, numRead); 
} 

I działa. Ale ... Czasami (bardzo rzadko, może 1 lub 2 razy dziennie) mój serwer nie otrzymuje danych. Mój dziennik klienta wygląda następująco:

Written A 
Written B 
Written C 
Written D 
Written E 

i tak dalej. Ale po stronie serwera to wygląda:

Received A 
Received E 

B, C, D rekordów danych nie zostały otrzymane, pomimo faktu, że po stronie klienta wygląda wszystkich danych została wysłana bez żadnych wyjątków!

Takie luki mogą być małe (2-3 minuty), co nie jest złe, ale czasami mogą być bardzo duże (1-2 godziny = 60-120 cykli) i jest to naprawdę problem dla moich klientów.

Naprawdę nie mam pojęcia, co może być nie tak. Dane wydają się być wysyłane przez klienta, ale nigdy nie docierają do serwera. Sprawdziłem to również z proxy.

Mam tylko dzienniki i nie mogę odtworzyć tego problemu (ale zdarza się to mojemu klientowi więcej niż jeden raz każdego dnia), aw dziennikach czasami widzę, że połączenie jest zerwane przez wyjątek "sendto failed: ECONNRESET (Połączenie resetowane przez peer) ". Następnie program zamyka gniazdo, ponownie inicjuje:

// close 
is.close(); 
os.close(); 
socket.close(); 

// reinitialize 
initSocket(); 

i próbuje ponownie zapisać dane zgodnie z powyższym opisem. Wtedy widzę problem: nawiązanie połączenia, pomyślne pisanie, ale na serwerze nie ma DANYCH!

Może to mieć coś wspólnego z ECONNRESET, może nie być, ale chcę o tym wspomnieć, ponieważ może być to ważne.

Byłbym bardzo wdzięczny za wszelkie pomysły i wskazówki.

P.S. Może to odgrywa pewną rolę: kod klienta działa na urządzeniu mobilnym z Androidem, które się porusza (jest w samochodzie). Połączenie internetowe jest ustanawiane przez GPRS.


UPD: Potrafię to odtworzyć! Przynajmniej częściowo (klient wysyła A, B, C, D, E, a serwer otrzymuje tylko A). Zdarza się, za każdym razem, gdy:

  1. nawiązaniu połączenia, klient czyta i pisze -> OK

  2. połączenie zostanie przerwane (wyłączyć router WLAN :)), stałem IOException, Zamykam strumienie i gniazdo -> OK

  3. Włączam router, połączenie się z powrotem, uruchamiam ponownie gniazdo, program wykonuje write() bez wyjątków, ale ... żadne dane nie docierają do serwera .

BTW ponieważ połączenie jest ponownie dostępny() zwraca zawsze 0.

+0

Jedną z rzeczy, które mogą pomóc, jest posiadanie serwera, który mógłby próbować zsynchronizować się z urządzeniem. Jeśli za pierwszym razem pominie dane, zawsze może spróbować ponownie - w zależności od tego, jak często sondujesz dane. – Max

+0

@max, jasne, masz rację. Ale serwer jest zamkniętym oprogramowaniem i nie mogę zmienić protokołu. – Valelik

+0

Nie można użyć 'ByteArrayOutputStream'? Coś [jak to] (http://stackoverflow.com/a/2984550/1134705) – jnthnjns

Odpowiedz

0

Przyczyną tego dziwnego zachowania było nie zamknięte gniazdo po stronie serwera. Mogłem go odtworzyć małym klientem i serwerem. Oba składają się z kilku linii kodu, który należy wykonać następujące czynności:

  1. połączyć się z serwerem
  2. symulowania martwy punkt (np wyłączyć WiFi)
  3. zamknąć gniazda po stronie klienta
  4. Nie zamykaj gniazdo po stronie serwera
  5. włączyć WiFi
  6. nawiązać nowe połączenie z klientem
  7. zapisu danych do tego połączenia

Voila! Klient zapisuje dane bez żadnych błędów, ale serwer ich nie otrzymuje ...

Ale jeśli serwer również zamknie gniazdo, serwer może odczytać te dane. Tak więc rozwiązaniem powinno być zamknięcie gniazda po przekroczeniu limitu czasu po stronie serwera.

Niestety w moim przypadku nie jest to możliwe, ponieważ serwer jest zastrzeżonym oprogramowaniem innych firm.

+2

Jest więc coś poważnie nie tak z serwerem. Jego odczyt na oryginalnym połączeniu powinien przerwać lub zablokować na zawsze lub uzyskać EOS, który powoduje, że zamyka to połączenie; i powinien pomyślnie odczytać nowe dane z nowego połączenia. Jeśli nie, jest to jednowątkowe lub ma inny problem ze współbieżnością. Nie rozumiem, dlaczego zaakceptowałeś to jako odpowiedź na własne pytanie, gdy w ogóle nie odpowiada, po prostu wyjaśnia sytuację, w której wystąpił błąd. To nie jest odpowiedź. – EJP

2

Pozbądź testu available(). Jeśli uczestnik ma odpowiedzieć, po prostu przeczytaj. W przeciwnym razie będziesz czytać odpowiedź, a czasem nie, a stracisz synchronizację. Istnieje bardzo mało poprawnych zastosowań available(), a to nie jest jedna z nich.

+0

dziękuję za sugestię, przepisuję kod, aby móc trwale odczytać dane bez blokowania pisania (BTW, czy możesz polecić lekturę dotyczącą wątków i networkingu?), Ale ... czy możesz wyjaśnić, w jaki sposób Twoja sugestia może pomóc Rozwiąż problem?Myślę, że robię coś złego podczas zamykania lub inicjowania. Więc gniazdo jest "otwarte" i "połączone", mogę "pisać" itp., Ale żadne dane nie są dostarczane do serwera. – Valelik

+0

@ Velelik Selektywne czytanie odpowiedzi w zależności od tego, jak szybko dotarła, nie może być poprawne, czyż nie? To, co teraz robisz, spowoduje każdy rodzaj problemu, jaki można sobie wyobrazić, od "brakujących danych", których nie czytałeś, do pisania bloków, do "zerowania połączenia przez peera". Daj nam znać, co się stało, gdy próbowałeś. – EJP

+0

Napisałem ponownie moją komunikację. A teraz mam dodatkowy wątek do czytania. Więc nie używam 'available()' teraz. Ale to nie pomogło. Mam ten sam problem. – Valelik

Powiązane problemy