Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Application TCP cliente qui ne detecte pas les coupures réseaux

2 réponses
Avatar
Olivier Merigon
Bonjour,
J'ai un probleme par rapport au comportement des Socket en Java:
On a un simple system client/server qui tourne sur deux machines
diferrentes.
Le client envoie des octets au serveur.
Le serveur recoie les octets et attent X secondes.
Pendant ce tps d'attente, on deconnect le serveur du réseau (simplement en
débranchant son cable réseau)
Apres le temps d'attente le serveur répond et se rend compte du pb réseaux
(une exception SocketException est lancé: connection reset, c'est parce que
on a essayé d'écrire sur la socket)
Mais coté client, on est toujours bloqué sur un recieve
(commandInput.readLine();), il se rendera jamais compte de la coupure
réseaux avec le serveur.
Meme apres une heure le client attend toujours la réponse d'un serveur avec
qui il n'a plus de connection.
Est'ce un comportement normaL ????

C'est tres génant car nous faisosn du FTP en mode S2S, et notre application
qui doit faire de tres gros transfer ne peut pas ce rendre compte du
plantage d'un transfert puisque l'on controle uniquement la socket de
command. On ne peut pas mettre de time out a cause de la durée des
transferts. L'application montrera des transfert en cours mais nous
attendons la réponse sur la socket de commande d'un serveur qui n'est plus
la....

Quelqu'un a une idée pour sortir de ce problème ?

Merci d'avance,

Ci dessous se trouve le code du client et du serveur que j'ai utilisé faire
l'expériene, le client est l'équivalent de telnet. Le serveur lui est
l'équivalent du service echo sauf qu'il interprete la commande 'wait X' ou X
est le nombre de seconde à attendre avant de répondre.


Olivier MERIGON


CLIENT:
----------------------------------------------------------------------------
-------

package com.iratensolutions.test.ftp;import java.io.BufferedReader;import
java.io.IOException;import java.io.InputStreamReader;import
java.io.OutputStreamWriter;import java.io.PrintWriter;import
java.net.Socket;/*** A Client/Server application to test the network failure
behavior with TCP.* This the client part. It just sends the keyboard input
to the server.* @author Olivier MERIGON*/public class
TestNetworkFailureClient {public static void main(String[] args) {if
(args.length != 1) {System.out.println("usage:
javacom.iratensolutions.test.ftp.TestNetworkFailureClient
serverAdress");}Socket commandSocket = null;BufferedReader
commandInput;BufferedReader keyboardInput;PrintWriter commandOutput;try
{commandSocket = new Socket(args[0], 666);commandInput = new
BufferedReader(newInputStreamReader(commandSocket.getInputStream()));keyboar
dInput = new BufferedReader(new InputStreamReader(System.in));commandOutput
= new PrintWriter(newOutputStreamWriter(commandSocket.getOutputStream()));}
catch (Exception e) {e.printStackTrace();return;}System.out.println("CLIENT
STARTED");String snd;String rcv = null;try {do {System.out.print("KEYBOARD:
");snd = keyboardInput.readLine();if (snd != null)
{commandOutput.println(snd);commandOutput.flush();System.out.println("SND: "
+ snd);rcv = commandInput.readLine();System.out.println("RCV: " + rcv);}}
while (rcv != null);} catch (IOException e1) {e1.printStackTrace();}}}

--------------------------------------------------------------------------

SERVER

----------------------------------------------------------------------

package com.iratensolutions.test.ftp;import java.io.DataInputStream;import
java.io.IOException;import java.io.PrintStream;import
java.net.ServerSocket;import java.net.Socket;/*** A Client/Server
application to test the network failure behavior with TCP.* This the server
part. The server can wait X second after responding to arequest.* If a wait
request is received, the server just answer the time waitedafter* the
requested wait time, otherwise it respond immediatly the requestnumber.*
usage: wait intNbSec | any text* @author Olivier MERIGON*/public class
TestNetworkFailureServer {public static void main(String args[])
{ServerSocket echoServer = null;String line;DataInputStream is;PrintStream
os;Socket clientSocket = null;try {echoServer = new
ServerSocket(666);System.out.println("SERVER STARTED");} catch (IOException
e) {System.out.println(e);}while (true) {try {clientSocket =
echoServer.accept();System.out.println("Handling new client...");is = new
DataInputStream(clientSocket.getInputStream());os = new
PrintStream(clientSocket.getOutputStream());int loopId = 0;do {line =
is.readLine();System.out.println("RCV: " + line);//Handle "Wait" commandif
(line.trim().startsWith("wait")) {String[] tab = line.split("\\s");boolean
ok = false;try {int nbSec =
Integer.parseInt(tab[1]);System.out.println("...waiting for " + nbSec + "
sec.");try {Thread.sleep(nbSec * 1000);} catch (InterruptedException e1)
{}String resp = "...end of wainting periode of " + nbSec + "
sec.";os.println(resp);System.out.println("SND: " + resp);ok = true;} catch
(Exception e) {ok = false;}if (!ok) {String resp = "usage: wait intNbSec |
any text";os.println(resp);System.out.println("SND: " + resp);}//Handle
"normal" action} else {os.println("# " + loopId);System.out.println("SND: #
" + loopId);}loopId++;} while (line != null);} catch (IOException e)
{System.out.println(e);}}}}

2 réponses

Avatar
Jean-Christophe Garnier
Bonjour,
Mes réponses dans votre description.


Bonjour,
J'ai un probleme par rapport au comportement des Socket en Java:
On a un simple system client/server qui tourne sur deux machines
diferrentes.
Le client envoie des octets au serveur.
Le serveur recoie les octets et attent X secondes.
Pendant ce tps d'attente, on deconnect le serveur du réseau (simplement en
débranchant son cable réseau)
Apres le temps d'attente le serveur répond et se rend compte du pb réseaux
(une exception SocketException est lancé: connection reset, c'est parce que
on a essayé d'écrire sur la socket)
Mais coté client, on est toujours bloqué sur un recieve
(commandInput.readLine();), il se rendera jamais compte de la coupure
réseaux avec le serveur.
Meme apres une heure le client attend toujours la réponse d'un serveur avec
qui il n'a plus de connection.
Est'ce un comportement normaL ????




Je crois bien que oui. Je me souviens d'un problème (en langage C, donc
rien à voir avec le langage mais plutôt avec TCP/IP) où le client ne
s'apercevait que le serveur n'était plus là que lorsqu'il essayait
d'écrire.

C'est tres génant car nous faisosn du FTP en mode S2S, et notre application
qui doit faire de tres gros transfer ne peut pas ce rendre compte du
plantage d'un transfert puisque l'on controle uniquement la socket de
command. On ne peut pas mettre de time out a cause de la durée des
transferts. L'application montrera des transfert en cours mais nous
attendons la réponse sur la socket de commande d'un serveur qui n'est plus
la....

Quelqu'un a une idée pour sortir de ce problème ?




Faire en sorte que le read de la réponse attendue par le client ne soit
pas bloquante. Pour cela, rien de plus simple. Voici le client modifié :

public class Client
{
public static void main (String[] args)
{
if(args.length != 1)
{
System.out.println ("usage:Client serverAdress");
}
Socket commandSocket = null;
BufferedReader commandInput;
BufferedReader keyboardInput;
PrintWriter commandOutput;
try
{
commandSocket = new Socket (args[0], 666);
---> commandSocket.setSoTimeout (10000); // Attente maxi 10 secondes
commandInput = new BufferedReader (new InputStreamReader
(commandSocket.getInputStream ()));
keyboardInput = new BufferedReader (new InputStreamReader
(System.in));
commandOutput= new PrintWriter (new OutputStreamWriter
(commandSocket.getOutputStream ()));
}
catch (Exception e)
{
e.printStackTrace ();
return;
}
System.out.println ("CLIENT STARTED");
String snd;
String rcv = null;
---> boolean toRead;
try
{
do
{
System.out.print ("KEYBOARD: ");
---> snd = "wait 15 toto";// à la place du
"keyboardInput.readLine ();" pour les tests
if (snd != null)
{
commandOutput.println (snd);
commandOutput.flush ();
System.out.println ("SND: "+ snd);
---> toRead = true;
---> while (toRead)
---> {
---> try
---> {
---> rcv = commandInput.readLine ();
---> toRead = false;
---> }
---> catch (java.net.SocketTimeoutException e)
---> {
---> System.out.println ("On a un TO sur le
read du client");
---> }
---> }
System.out.println ("RCV: " + rcv);
}
}
while (rcv != null);
}
catch (IOException e1)
{
e1.printStackTrace ();
}
}
}
Avec ce mécanisme, le client se réveille toutes les 10 secondes. S'il
n'a rien lu ou qu'il est réveillé par le système comme demandé, il
retourne en lecture. Si une autre exception survient ou qu'il a lu
quelque chose, il continue le traitement.
Je n'ai pas les moyens ici de tester avec un vrai réseau, mais je pense
que le simple fait de se remettre en lecture avec un serveur qui n'est
plus présent devrait suffire à lever une exception du type IOException.
Sinon vous pouvez tester l'état de la socket avant chaque retour en
lecture (par exemple socket.isBound() ou isClosed() ou
isOutputShutdown(), etc.)

Merci d'avance,

Ci dessous se trouve le code du client et du serveur que j'ai utilisé faire
l'expériene, le client est l'équivalent de telnet. Le serveur lui est
l'équivalent du service echo sauf qu'il interprete la commande 'wait X' ou X
est le nombre de seconde à attendre avant de répondre.


Olivier MERIGON


CLIENT:
----------------------------------------------------------------------------
-------

package com.iratensolutions.test.ftp;import java.io.BufferedReader;import
java.io.IOException;import java.io.InputStreamReader;import
java.io.OutputStreamWriter;import java.io.PrintWriter;import
java.net.Socket;/*** A Client/Server application to test the network failure
behavior with TCP.* This the client part. It just sends the keyboard input
to the server.* @author Olivier MERIGON*/public class
TestNetworkFailureClient {public static void main(String[] args) {if
(args.length != 1) {System.out.println("usage:
javacom.iratensolutions.test.ftp.TestNetworkFailureClient
serverAdress");}Socket commandSocket = null;BufferedReader
commandInput;BufferedReader keyboardInput;PrintWriter commandOutput;try
{commandSocket = new Socket(args[0], 666);commandInput = new
BufferedReader(newInputStreamReader(commandSocket.getInputStream()));keyboar
dInput = new BufferedReader(new InputStreamReader(System.in));commandOutput
= new PrintWriter(newOutputStreamWriter(commandSocket.getOutputStream()));}
catch (Exception e) {e.printStackTrace();return;}System.out.println("CLIENT
STARTED");String snd;String rcv = null;try {do {System.out.print("KEYBOARD:
");snd = keyboardInput.readLine();if (snd != null)
{commandOutput.println(snd);commandOutput.flush();System.out.println("SND: "
+ snd);rcv = commandInput.readLine();System.out.println("RCV: " + rcv);}}
while (rcv != null);} catch (IOException e1) {e1.printStackTrace();}}}

--------------------------------------------------------------------------

SERVER

----------------------------------------------------------------------

package com.iratensolutions.test.ftp;import java.io.DataInputStream;import
java.io.IOException;import java.io.PrintStream;import
java.net.ServerSocket;import java.net.Socket;/*** A Client/Server
application to test the network failure behavior with TCP.* This the server
part. The server can wait X second after responding to arequest.* If a wait
request is received, the server just answer the time waitedafter* the
requested wait time, otherwise it respond immediatly the requestnumber.*
usage: wait intNbSec | any text* @author Olivier MERIGON*/public class
TestNetworkFailureServer {public static void main(String args[])
{ServerSocket echoServer = null;String line;DataInputStream is;PrintStream
os;Socket clientSocket = null;try {echoServer = new
ServerSocket(666);System.out.println("SERVER STARTED");} catch (IOException
e) {System.out.println(e);}while (true) {try {clientSocket >echoServer.accept();System.out.println("Handling new client...");is = new
DataInputStream(clientSocket.getInputStream());os = new
PrintStream(clientSocket.getOutputStream());int loopId = 0;do {line >is.readLine();System.out.println("RCV: " + line);//Handle "Wait" commandif
(line.trim().startsWith("wait")) {String[] tab = line.split("s");boolean
ok = false;try {int nbSec >Integer.parseInt(tab[1]);System.out.println("...waiting for " + nbSec + "
sec.");try {Thread.sleep(nbSec * 1000);} catch (InterruptedException e1)
{}String resp = "...end of wainting periode of " + nbSec + "
sec.";os.println(resp);System.out.println("SND: " + resp);ok = true;} catch
(Exception e) {ok = false;}if (!ok) {String resp = "usage: wait intNbSec |
any text";os.println(resp);System.out.println("SND: " + resp);}//Handle
"normal" action} else {os.println("# " + loopId);System.out.println("SND: #
" + loopId);}loopId++;} while (line != null);} catch (IOException e)
{System.out.println(e);}}}}






Avatar
Olivier Merigon
Merci pour votre réponse.
J'avais essayer cette approche, mais en fait meme apres le time-out et la
relecture aucune exception n'est lever.
Par contre j'ai trouver quelquechose, en activant l'option SO_KEEPALIVE, le
client s'appercoit de la deconnection au bout de deux heures (le serveur est
pinger toutes les deux heures en fait).

Olivier



"Jean-Christophe Garnier" a écrit dans le
message de news:40fc3fc1$0$29372$
Bonjour,
Mes réponses dans votre description.


Bonjour,
J'ai un probleme par rapport au comportement des Socket en Java:
On a un simple system client/server qui tourne sur deux machines
diferrentes.
Le client envoie des octets au serveur.
Le serveur recoie les octets et attent X secondes.
Pendant ce tps d'attente, on deconnect le serveur du réseau (simplement
en


débranchant son cable réseau)
Apres le temps d'attente le serveur répond et se rend compte du pb
réseaux


(une exception SocketException est lancé: connection reset, c'est parce
que


on a essayé d'écrire sur la socket)
Mais coté client, on est toujours bloqué sur un recieve
(commandInput.readLine();), il se rendera jamais compte de la coupure
réseaux avec le serveur.
Meme apres une heure le client attend toujours la réponse d'un serveur
avec


qui il n'a plus de connection.
Est'ce un comportement normaL ????




Je crois bien que oui. Je me souviens d'un problème (en langage C, donc
rien à voir avec le langage mais plutôt avec TCP/IP) où le client ne
s'apercevait que le serveur n'était plus là que lorsqu'il essayait
d'écrire.

C'est tres génant car nous faisosn du FTP en mode S2S, et notre
application


qui doit faire de tres gros transfer ne peut pas ce rendre compte du
plantage d'un transfert puisque l'on controle uniquement la socket de
command. On ne peut pas mettre de time out a cause de la durée des
transferts. L'application montrera des transfert en cours mais nous
attendons la réponse sur la socket de commande d'un serveur qui n'est
plus


la....

Quelqu'un a une idée pour sortir de ce problème ?




Faire en sorte que le read de la réponse attendue par le client ne soit
pas bloquante. Pour cela, rien de plus simple. Voici le client modifié :

public class Client
{
public static void main (String[] args)
{
if(args.length != 1)
{
System.out.println ("usage:Client serverAdress");
}
Socket commandSocket = null;
BufferedReader commandInput;
BufferedReader keyboardInput;
PrintWriter commandOutput;
try
{
commandSocket = new Socket (args[0], 666);
---> commandSocket.setSoTimeout (10000); // Attente maxi 10
secondes

commandInput = new BufferedReader (new InputStreamReader
(commandSocket.getInputStream ()));
keyboardInput = new BufferedReader (new InputStreamReader
(System.in));
commandOutput= new PrintWriter (new OutputStreamWriter
(commandSocket.getOutputStream ()));
}
catch (Exception e)
{
e.printStackTrace ();
return;
}
System.out.println ("CLIENT STARTED");
String snd;
String rcv = null;
---> boolean toRead;
try
{
do
{
System.out.print ("KEYBOARD: ");
---> snd = "wait 15 toto";// à la place du
"keyboardInput.readLine ();" pour les tests
if (snd != null)
{
commandOutput.println (snd);
commandOutput.flush ();
System.out.println ("SND: "+ snd);
---> toRead = true;
---> while (toRead)
---> {
---> try
---> {
---> rcv = commandInput.readLine ();
---> toRead = false;
---> }
---> catch (java.net.SocketTimeoutException e)
---> {
---> System.out.println ("On a un TO sur le
read du client");
---> }
---> }
System.out.println ("RCV: " + rcv);
}
}
while (rcv != null);
}
catch (IOException e1)
{
e1.printStackTrace ();
}
}
}
Avec ce mécanisme, le client se réveille toutes les 10 secondes. S'il
n'a rien lu ou qu'il est réveillé par le système comme demandé, il
retourne en lecture. Si une autre exception survient ou qu'il a lu
quelque chose, il continue le traitement.
Je n'ai pas les moyens ici de tester avec un vrai réseau, mais je pense
que le simple fait de se remettre en lecture avec un serveur qui n'est
plus présent devrait suffire à lever une exception du type IOException.
Sinon vous pouvez tester l'état de la socket avant chaque retour en
lecture (par exemple socket.isBound() ou isClosed() ou
isOutputShutdown(), etc.)

Merci d'avance,

Ci dessous se trouve le code du client et du serveur que j'ai utilisé
faire


l'expériene, le client est l'équivalent de telnet. Le serveur lui est
l'équivalent du service echo sauf qu'il interprete la commande 'wait X'
ou X


est le nombre de seconde à attendre avant de répondre.


Olivier MERIGON


CLIENT:


---------------------------------------------------------------------------
-

-------

package com.iratensolutions.test.ftp;import java.io.BufferedReader;import
java.io.IOException;import java.io.InputStreamReader;import
java.io.OutputStreamWriter;import java.io.PrintWriter;import
java.net.Socket;/*** A Client/Server application to test the network
failure


behavior with TCP.* This the client part. It just sends the keyboard
input


to the server.* @author Olivier MERIGON*/public class
TestNetworkFailureClient {public static void main(String[] args) {if
(args.length != 1) {System.out.println("usage:
javacom.iratensolutions.test.ftp.TestNetworkFailureClient
serverAdress");}Socket commandSocket = null;BufferedReader
commandInput;BufferedReader keyboardInput;PrintWriter commandOutput;try
{commandSocket = new Socket(args[0], 666);commandInput = new


BufferedReader(newInputStreamReader(commandSocket.getInputStream()));keyboa
r

dInput = new BufferedReader(new
InputStreamReader(System.in));commandOutput


= new
PrintWriter(newOutputStreamWriter(commandSocket.getOutputStream()));}


catch (Exception e)
{e.printStackTrace();return;}System.out.println("CLIENT


STARTED");String snd;String rcv = null;try {do
{System.out.print("KEYBOARD:


");snd = keyboardInput.readLine();if (snd != null)


{commandOutput.println(snd);commandOutput.flush();System.out.println("SND:
"

+ snd);rcv = commandInput.readLine();System.out.println("RCV: " + rcv);}}
while (rcv != null);} catch (IOException e1) {e1.printStackTrace();}}}



--------------------------------------------------------------------------

SERVER

----------------------------------------------------------------------

package com.iratensolutions.test.ftp;import
java.io.DataInputStream;import


java.io.IOException;import java.io.PrintStream;import
java.net.ServerSocket;import java.net.Socket;/*** A Client/Server
application to test the network failure behavior with TCP.* This the
server


part. The server can wait X second after responding to arequest.* If a
wait


request is received, the server just answer the time waitedafter* the
requested wait time, otherwise it respond immediatly the requestnumber.*
usage: wait intNbSec | any text* @author Olivier MERIGON*/public class
TestNetworkFailureServer {public static void main(String args[])
{ServerSocket echoServer = null;String line;DataInputStream
is;PrintStream


os;Socket clientSocket = null;try {echoServer = new
ServerSocket(666);System.out.println("SERVER STARTED");} catch
(IOException


e) {System.out.println(e);}while (true) {try {clientSocket > >echoServer.accept();System.out.println("Handling new client...");is = new
DataInputStream(clientSocket.getInputStream());os = new
PrintStream(clientSocket.getOutputStream());int loopId = 0;do {line > >is.readLine();System.out.println("RCV: " + line);//Handle "Wait"
commandif


(line.trim().startsWith("wait")) {String[] tab line.split("s");boolean
ok = false;try {int nbSec > >Integer.parseInt(tab[1]);System.out.println("...waiting for " + nbSec + "
sec.");try {Thread.sleep(nbSec * 1000);} catch (InterruptedException e1)
{}String resp = "...end of wainting periode of " + nbSec + "
sec.";os.println(resp);System.out.println("SND: " + resp);ok = true;}
catch


(Exception e) {ok = false;}if (!ok) {String resp = "usage: wait intNbSec
|


any text";os.println(resp);System.out.println("SND: " + resp);}//Handle
"normal" action} else {os.println("# " + loopId);System.out.println("SND:
#


" + loopId);}loopId++;} while (line != null);} catch (IOException e)
{System.out.println(e);}}}}