I have the following problem:
System.in
and sending it via SocketSystem.in
when a error occurs in itWhen I have a problem in method2, I have to press ENTER
twice, because, even it closing the socket, the readLine()
on method1 was already executed, so it first read the line for method1, then it takes the input for method2.
Edit: The method1 is constantly receiving messages from the socket and method2 is sending everything I type on console via Socket. But when the receive of messages fail, I want to just ask if the client wants to connect to other server, but the method1 already read the line, so the first time i type goes to the now useless method1, then the second line goes correctly to method2
What can I do in this case?
Observation: I know in the example I can make the reader as a class property. Just made this way to make it easier to understand
public class App {
public void method1() {
new Thread(() -> {
String line;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
while (!socket.isClosed() && line = bufferedReader.readLine() != null) {
//Keeps reading from the System.in and sending to the Socket
}
}).start();
}
public void method2() {
try {
//Keeps receiving messages from the Socket
} catch (Exception e) {
socket.close();
String line;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
line = bufferedReader.readLine();
//Asks if the user want to connect to other server
}
}
}
There is no easy way to do that because System.in
is a bare InputStream, which is uninterruptible, unstoppable, and will block the caller until it is closed or EOF is reached.
One ugly solution is to create a new thread and stop the old thread. However, this requires using the deprecated Thread.stop()
method.
public class App {
private Thread sender;
private void stopSender() {
if (sender != null) {
sender.stop();
sender = null;
}
}
private void startSender() {
// stop previous sender if necessary
stopSender();
sender = new Thread(() -> String line;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
while (!socket.isClosed() && line = bufferedReader.readLine() != null) {
//Keeps reading from the System.in and sending to the Socket
}
});
sender.start();
}
public void method2() {
try {
//Keeps receiving messages from the Socket
} catch (Exception e) {
// stop sender first
stopSender();
socket.close();
String line;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
line = bufferedReader.readLine();
//Asks if the user want to connect to other server
// start a new sender
startSender();
}
}
Alternatively, there is a more elegant but complex solution: use non-blocking I/O. However, Java doesn't support selectable System.in
directly, so you would need to write JNI/JNA code.
Anyway, there is no easy solution to this.