2010-06-29 5 views
7

Abbiamo una semplice architettura di server client tra il nostro dispositivo mobile e il nostro server scritti entrambi in Java. Un'implementazione ServerSocket e Socket estremamente semplice. Tuttavia, un problema è che quando il client termina bruscamente (senza chiudere correttamente il socket) il server non sa che è disconnesso. Inoltre, il server può continuare a scrivere su questo socket senza ottenere eccezioni. Perché?Il socket Java non genera eccezioni su una presa morta?

Secondo la documentazione, i socket Java dovrebbero generare eccezioni se si tenta di scrivere su un socket che non è raggiungibile dall'altra parte!

risposta

0

Le comunicazioni TCP/IP possono essere molto strane. TCP tenterà ancora per un po 'ai livelli inferiori dello stack senza mai lasciare che i livelli superiori sappiano che qualcosa è successo.

Mi aspetto che dopo un po 'di tempo (da 30 secondi a qualche minuto) dovresti vedere un errore, ma non ho ancora provato questo, sto solo andando fuori dal modo in cui le app TCP tendono a funzionare.

Si potrebbe essere in grado di stringere le specifiche TCP (riprovare, timeout, ecc.) Ma, di nuovo, non si è incasinato molto.

Inoltre, è possibile che io sia totalmente sbagliato e che l'implementazione di Java che si sta utilizzando sia semplicemente instabile.

2

La connessione verrà eventualmente scaduta da Retransmit Timeout (RTO). Tuttavia, il RTO è calcolato utilizzando un algoritmo complicato sulla base di latenza di rete (RTT), si veda questo RFC,

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

Quindi, su una rete mobile, questo può essere minuti. Attendi 10 minuti per vedere se riesci a ottenere un timeout.

La soluzione a questo tipo di problema consiste nell'aggiungere un battito cardiaco nel proprio protocollo dell'applicazione e interrompere la connessione quando non si ottiene ACK per l'heartbeat.

1

La parola chiave qui (without closing the socket properly).

Sockets dovrebbero essere sempre acquisite e trasferite in questo modo:

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

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

anche con questo precauzioni è necessario specificare i timeout di applicazioni, specifiche per il protocollo.

La mia esperienza ha dimostrato, che purtroppo non è possibile utilizzare nessuna delle funzionalità timeout Socket affidabile (ad esempio non v'è alcun timeout per le operazioni di scrittura e anche leggere le operazioni possono, a volte, appendere per sempre).

Ecco perché è necessario un thread di controllo che applica i timeout dell'applicazione e dispone di socket che non rispondono per un po '.

Un modo conveniente per farlo è inizializzando Socket e ServerSocket tramite i canali corrispondenti in java.nio. Il vantaggio principale di tali socket è che sono interrompibili, in questo modo è possibile semplicemente interrompere il thread che esegue il protocollo socket e assicurarsi che il socket sia correttamente eliminato.

Si noti che è necessario imporre il timeout dell'applicazione su entrambi i lati, in quanto è solo una questione di tempo e sfortuna in cui si potrebbero verificare socket non responsivi.

0

Per rispondere alla prima parte della domanda (sul non sapere che il client si è interrotto bruscamente), in TCP, non è possibile sapere se una connessione è terminata finché non si tenta di utilizzarla.

La nozione di guaranteed delivery in TCP è piuttosto sottile: la consegna non è effettivamente garantita all'applicazione dall'altra parte (dipende da cosa significa realmente garantito). Section 2.6 of RFC 793 (TCP) fornisce maggiori dettagli su questo argomento. This thread on the Restlet-discuss list e this thread on the Linux kernel list potrebbero anche essere di interesse.

Per la seconda parte (non rilevando quando si scrive su questo socket), questa è probabilmente una questione di buffer e timeout (come altri hanno già suggerito).

+0

Ho già provato ad usarlo scrivendo sul socket e anche in questo caso non so se il client è disconnesso. – erotsppa

0

Sto affrontando lo stesso problema. Penso che quando si registra il socket con un selettore non si creino eccezioni. Stai usando un selettore con il tuo socket?