This question already has answers here:
How to interrupt BufferedReader's readLine
(10 answers)
How to properly stop the Thread in Java?
(9 answers)
Closed 4 years ago.
I am trying to terminate the child thread, that's waiting for the input from the server. I've tried to do it with the flag, but it stops on the
message = serverReader.readLine() && !isClosed(),
because it waits for the input from the server and only after this input it checks the flag and interrupts. But it's not a good solution, cause i couldn't stop it without server message.
I also tried to check firstly the flag and then readline(), but it doesn't work too.
Is it any good solutions for that?
#Override
public void run() {
String message;
try {
while((message = serverReader.readLine()) != null && !isClosed()) {
consoleWriter.println("Other user: " + message);
consoleWriter.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void setUpNetworking() {
try {
Socket socket = new Socket("127.0.0.1", 5000);
InputStreamReader streamReader = new InputStreamReader(socket.getInputStream());
serverWriter = new PrintWriter(socket.getOutputStream());
serverReader = new BufferedReader(streamReader);
//Starting listening messages from server
incomeReader = new Thread(new IncomeMessagesReader(serverReader, consoleWriter, this));
incomeReader.start();
System.out.println("Networking established");
} catch (IOException e) {
e.printStackTrace();
}
}
Swap the && order. The && operator is short-circuit, so the right side won't execute if the left side fails. The opposite is true for ||.
while (!isClosed() && readLine())
Related
I have a buffered reader reading from a socket line by line. So this works fine. However this looks pretty low level to me and a telnet client is not able to close the connection sending a ctrl + c. So I am wondering if there is some nicer implementation of a stream reader? I.e. the whole tread and loop could easily be abstracted away and just call lambda functions on read, close and error. Or what is the best practice here?
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
new Thread(() -> {
while (true) {
try {
String readLine = bufferedReader.readLine();
// if readline is null then the client just closed connection
// if there is something in the buffer and the clients close the connection
// raadLine returns with anything left in the buffer up until the client left
// and returns a second time with null
if (readLine == null) {
logger.info("client closed connection");
socket.close();
disconnectAll();
break;
} else {
for (Listener listener : listeners) {
listener.messageReceived(this, readLine);
}
}
} catch (IOException | IllegalAccessException | InvocationTargetException e) {
logger.error(e.getMessage(), e);
try {
socket.close();
} catch (IOException e1) {
logger.error(e1.getMessage(), e1);
} finally {
disconnectAll();
break;
}
}
}
}).start();
I think your base problem is that sending Ctrl-C doesn't close a stream, Ctrl-D does. Edit: Ctrl-Z on Windows.
The remainder of the question really belongs to https://codereview.stackexchange.com/, but here goes.
Firstly, you are closing a socket that was opened outside.
Secondly, you shouldn't create Thread objects, but use an ExecutorService.
Third, I'd recommend using try-with-resource to ensure everything closes automatically.
Fourth, you can use the read line in your while statement instead of using while(true) - break.
This gives you something like
ExecutorService readerExecutor = Executors.newSingleThreadExecutor();
public startReadingSocket(Supplier<Socket> createSocket, Consumer<String> lineHandler, Consumer<Exception> excHandler, Runnable cleanUp) {
readerExecutor.submit(() -> {
String readLine;
try (Socket s = createSocket.get();
InputStreamReader isReader = new InputStreamReader(s.getInputStream());
BufferedReader reader = new BufferedReader(isReader)) {
while (readLine = reader.readLine() != null) {
lineHandler.accept(readLine);
}
System.out.println("client closed connection.");
} catch (Exception e) {
excHandler.accept(e);
} finally {
cleanUp.run();
}
}
}
And you can run that via
startReadingSocket(() -> new Socket(host, port),
line -> listeners.forEach(l -> l.messageReceived(this, line)),
ex -> logger.error(ex.getMessage, ex),
this::disconnectAll);
Now this is Java 8, with previous versions you'd need to create interfaces and anonymous classes for the lambdas.
This question already has an answer here:
Java networking, really strange error
(1 answer)
Closed 8 years ago.
Im working on a little chat program and now i have a huge problem and i can not solve it.
I dont know where the mistake could be, for me the code is right. So i really really need help. I have 2 threads in my server, 1 thread for accepting clients and the other for the streams. And the thread for the streams is not working right. It sends only 1 time a message back to the client and multiple clients are also not working. And there is another strange problem. I can only send 1 message back, if i put the JOptionPane-message called "Sockets empty" in the else statement, without it doesnt work.
Here is the stream thread code:
private static Runnable streamThread = new Runnable()
{
public void run()
{
while(true)
{
if(!(socketList.isEmpty()))
{
for(int i = 0; i < socketList.size(); i++)
{
try
{
String key = socketList.get(i);
if(socketHashMap.containsKey(key))
{
Socket connection = socketHashMap.get(key);
ObjectInputStream ois = new ObjectInputStream(connection.getInputStream());
String response = (String) ois.readObject();
ObjectOutputStream oos = new ObjectOutputStream(connection.getOutputStream());
oos.writeObject(key + ": " + response);
oos.flush();
}
if(connection.isClosed())
{
JOptionPane.showMessageDialog(null, "Client closed connection", "Info", JOptionPane.INFORMATION_MESSAGE);
}
}
catch (IOException | ClassNotFoundException e) {
JOptionPane.showMessageDialog(null, "ERROR: " + e.getMessage(), "ALARM", JOptionPane.ERROR_MESSAGE);
try {
connection.close();
connection.shutdownInput();
connection.shutdownOutput();
listClientsModel.remove(i);
} catch (IOException e1) {
}
}
}
}
else
{
JOptionPane.showMessageDialog(null, "SOCKETS LEER", "Info", JOptionPane.INFORMATION_MESSAGE);
}
}
}
};
And if you want to see the complete servercode :
http://pastebin.com/sxGGRnJv
The documentation for getOutputStream says:
Closing the returned OutputStream will close the associated socket.
And that is the problem. You create an ObjectOutputStream, but don't keep a reference to that object around. As this object gets garbage collected, it will call close() which will close the socket's output stream.
Same problem with the InputStream.
You could, for example, create a class that contains your socket and input and output stream and store that in your map instead of just the socket. That way you can re-use the streams.
I have 2 sockets and I am using BufferedReader around it's InputStreams. What I am trying to do is take all input from the first socket and send it to the other socket (and visa versa).
The problem is that if the first one does not send a message, it will still block on the first readLine() even though the 2nd socket has already sent some data and is ready. I would like to continue with this simple approach of using no additional threads.
Here's some code that I wrote up, as you can see I have 2 BufferedReaders (in0 and in1) , the program gets stuck at in0.readLine() (blocking).
private void network()
{
PrintWriter out0 = null, out1 = null;
BufferedReader in0 = null,in1 = null;
try{
//clients[] is an array of Socket[2]
in0 = new BufferedReader(new InputStreamReader(clients[0].getInputStream()));
out0 = new PrintWriter(clients[0].getOutputStream(), true);
in1 = new BufferedReader(new InputStreamReader(clients[1].getInputStream()));
out1 = new PrintWriter(clients[1].getOutputStream(), true);
} catch (IOException e) {
System.out.println("Accept failed: 4445");
System.exit(-1);
}
int count = 1;
while(true)
{
System.out.println("network check loop # " + count);
++count;
String nextMessage = null;
try {
if( (nextMessage = in0.readLine()) != null)
{
this.relayMessage(nextMessage,out1);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Middle of network check loop");
nextMessage = null;
try {
if((nextMessage = in1.readLine()) != null)
{
this.relayMessage(nextMessage,out0);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
How can I just skip that statement if in0 is not ready to give me some data? I have seen BufferedReader's ready() method and have attempted to use in0.ready() && readLine() but this causes an infinite loop as neither of the bufferedreaders appear to ever be 'ready'. As well, I am certain that the messages being sent over the socket end in newline characters so readLine() should process correctly!
Any ideas?
Try to use setSoTimeout to put a timeout on your read(), then you just need to catch the SocketTimeoutException if the timer has expired.
Here break and continue keywords are your friends.
The simplest approach is to use two threads. This way you don't have to write your own scheduling code to determine which thread should be running. BTW: The code to copy from one socket to another is the same in each thread, reducing duplication.
To manage your threads I would use an ExecutorService which will make shutting downt eh threads easier.
I got a socket listener which keep listening for data. The problem now is that the client which send data will finally close the connection by itself. Based on my codes below I am wondering do I still need to perform this part of the codes where it does writeBuffer.close();?
Should I remove the final part and just put the socket closing the catch?
public void run()
{
BufferedWriter writeBuffer = null;
BufferedReader readBuffer = null;
String message="";
try {
writeBuffer = new BufferedWriter(new OutputStreamWriter(receivedSocketConn1.getOutputStream()));
readBuffer = new BufferedReader(new InputStreamReader(receivedSocketConn1.getInputStream()));
int m = 0, count=0;
int nextChar=0;
while ((nextChar=readBuffer.read()) != -1)
{
message += (char) nextChar;
if (nextChar == '#')
{
System.out.println("\n\nSending PA : "+message);
writeBuffer.write("$PA\r\n");
writeBuffer.flush();
message="";
}
}
}
catch (Exception ex)
{
System.out.println("MyError:Exception has been caught in in the main first try");
ex.printStackTrace(System.out);
}
/*finally
{
try
{
if ( writeBuffer != null )
{
writeBuffer.close();
}
else
{
System.out.println("MyError:writeBuffer is null in finally close");
}
}
catch(IOException ex)
{
ex.printStackTrace(System.out);
}
}*/
}
It's always a good idea to explicitly close the connections you're using. Think about it, it might be possible that the client never closes the connection (of course, then you'd have to implement some kind of timeout mechanism that closes the connection on the server side after a certain amount of time, but that's a different matter).
My point is - it never hurts to be careful, and manage your resources in a conservative fashion.
I'm writing a basic Server-client program in Java and I'm trying to handle the case where the client terminates unexpectedly.
public void run() {
while(alive) {
try {
// socketIn is a BufferedReader wrapped around the socket's InputStream.
String input = socketIn.readLine();
if(input == null)
continue;
String response = processInput(input);
// socketOut is a PrintWriter wrapped around the socket's OutputStream.
if(response != null) {
socketOut.println(response);
socketOut.flush();
}
} catch(IOException e) {
System.out.println("TRACE 1");
alive = false;
}
}
System.out.println("TRACE 2");
}
But when I kill the client, the loop keeps going and neither TRACE is printed out. I'm assuming that when a socket is closed from the other end and I am trying to read from it, it will throw an IOException.
Was this a bad assumption? What can I do to fix this?
readLine() will return null at end of stream, which is what happens when the remote end closes the connection normally. You are attempting to continue on this condition, which will loop forever. IOException will be thrown if the connection is broken abnormally.