In article <resvjr$k3$***@gwaiyur.mb-net.net>, ***@freenet.de
says...
Post by Michael Paapdo {
socket = new Socket();
try {
socket.connect(isa, 5000);
}
catch (ConnectException ce) {
ce.printStackTrace();
}
catch (SocketException se) {
se.printStackTrace();
}
catch (UnknownHostException uhe) {
uhe.printStackTrace();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
try {
Thread.sleep(5000);
System.out.println("Verbinde...");
}
catch(InterruptedException ie) {
ie.printStackTrace();
}
}
while (!socket.isConnected());
Fieses Try/Catch-Gewitter.
1. Try-with resources verwenden, denn einen Socket kann man schließen,
und sollte man auch schließen, in einem finally-Block. Das wird leider
selten richtig gemacht, darum haben sich die Designer von Java
irgendwann ein wundervolles Konstrukt ausgedacht: "Try with resources".
try (final var socket = new Socket()){
socket.connect(isa, 5000);
} catch( ....
Die Variablen sind dann auch nur innerhalb dieses Blocks sichtbar, was
grundsätzlich schön ist.
2. Catch-Blöcke kann man zusammenführen, wenn die eh alle das Gleiche
machen:
try (final var socket = new Socket()){
socket.connect(isa, 5000);
} catch( ConnectException | SocketException | UnknownHostException
| IOException ex) {
ex.printStackTrace();
}
3. Weil deine Connect-Exception eine völlig erwartete Aktion ist, willst
du sie ggf anders behandeln. Weil sie ein Untertyp von IOException ist,
musst du sie vorher fangen:
try (final var socket = new Socket()){
socket.connect(isa, 5000);
} catch (ConnectException ex){
System.out.println("will retry connection...");
} catch( SocketException | UnknownHostException
| IOException ex) {
ex.printStackTrace();
}
4. nun zum Retry und Sleep:
Wenn dein Sleep rüde unterbrochen wird, dann in der Regel, weil jemand
versucht den Thread zu beenden. Das ignoriert man nicht einfach, sondern
man sollte tun, wie einem befohlen wurde. Die Exception ist dazu da,
darauf reagieren zu könne, wenn es nötig ist. Ist es aber nicht.
Außerdem solltest du den Socket wieder verwenden, um Resourcen zu
sparen. Dazu bieten sich geschachtelte try/catches an:
try (final var socket = new Socket()){
do {
try {
socket.connect(isa, 5000);
} catch (ConnectException ex){
System.out.println("will retry connection...");
thread.sleep(5000):
}
} while (!socket.isConnected());
} catch( SocketException | UnknownHostException
| IOException | InterruptedException ex) {
ex.printStackTrace();
}
Und schon sieht der Code ein ganzes Stück kürzer und sauberer aus. Und
wenn ich nichts falsch gemacht habe, funktioniert er auch korrekter.
5. Diese Schachtellung hier mit einem Haufen Code zu füllen, der den
Socket verwendet, ist wahrscheinlich keine gute Idee, weil's schlecht
aussieht. Eine Methode sollte nicht zu viel tun. Besser man injiziert
den Code, der den Socket verwenden soll, oder man gibt den Socket
zurück. Lass mich ein Beispiel geben, wie man auszuführenden Code
injizieren kann:
void sendDataOverSocket(Socket socket){
//do something with socket
}
void sendDataToService(){
connectSocketAndDo(this::sendDataOverSocket);
}
void connectSocketAndDo(Consumer<Socket> job){
try (final var socket = new Socket()){
do {
try {
socket.connect(isa, 5000);
job.accept(socket);
} catch (ConnectException ex){
System.out.println("will retry connection...");
thread.sleep(5000):
}
} while (!socket.isConnected());
} catch( SocketException | UnknownHostException
| IOException | InterruptedException ex) {
ex.printStackTrace();
}
}
6. (Hausaufgabe) Es ist selten gut, wenn der Service ewig probiert, ggf.
wäre es sinvoll ein Limit für Retries zu setzen.
Gruß,
-Wanja-
--
..Alesi's problem was that the back of the car was jumping up and down
dangerously - and I can assure you from having been teammate to
Jean Alesi and knowing what kind of cars that he can pull up with,
when Jean Alesi says that a car is dangerous - it is. [Jonathan Palmer]