multithreaded TCP server: java.net.SocketException: Socket closed - java

My code is as follows. When request comes, server creates two threads (producer-consumer pattern):
...
while(true) {
Socket clientSocket = server.accept();
System.out.println("Got connection!");
Thread consumerThread = new Thread(new ConsumerThread(sharedQueue, clientSocket));
Thread producerThread = new Thread(new ProducerThread(sharedQueue, clientSocket));
consumerThread.start();
producerThread.start();
}
...
Consumer thread reads what client sent and producer thread responds back. Consumer:
#Override
public void run() {
try {
while (true) {
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// read, do actions
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Producer:
#Override
public void run() {
try {
out = new PrintStream(clientSocket.getOutputStream(), true);
// some actions
out.println("something");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
out.close();
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
But in server I get following error:
java.net.SocketException: Socket closed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:150)
at java.net.SocketInputStream.read(SocketInputStream.java:121)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at ee.ut.ds.server.ConsumerThread.run(ConsumerThread.java:30)
at java.lang.Thread.run(Thread.java:745)
What might cause this? I even see that client accepts message correctly. Also, in producer thread I close a socket. I do not understand.

You closed the socket and continued to use it.
Don't close the socket, or its output stream, until you have read end of stream from the BufferedReader.
Construct the BufferedReader outside the loop.
You probably don't need two threads per socket.

You are starting both the threads in parallel. You can't predict the behvaiour of threads. You are using the same socket for both the threads and if producer thread starts you are closing socket in finally section.
you should not close the connection and make sure the race condition should not occur.

The problem is because you are closing the socket from your produce after writing something to it.
If you want the socket to be open, just close the output stream in the finally block in Producer.
You can close the socket from Server/Producer/Consumer once you are sure that there is no more network I/O to happen over the socket.
https://docs.oracle.com/javase/7/docs/api/java/net/Socket.html#close()

Related

ThreadPoolExecutor.shutdownNow() not throwing InterruptedException in Thread

I am implementing a Transfer Server program which takes messages from clients (via console input) and then forwards it to some sort of mailbox.
To allow concurrent reception of several messages by different clients, I first created a class that implements the Runnable interface. Each of this class instances will handle the communication with exactly one client:
public class ClientConnection implements Runnable {
//...
//...
#Override
public void run() {
try {
// prepare the input reader and output writer
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true);
Message message = new Message();
String request = "";
// read client requests
while ((request = reader.readLine()) != null) {
System.out.println("Client sent the following request: " + request);
String response;
if (request.trim().equals("quit")) {
writer.println("ok bye");
return;
}
response = message.parseRequest(request);
if (message.isCompleted()) {
messagesQueue.put(message);
message = new Message();
}
writer.println(response);
}
} catch (SocketException e) {
System.out.println("ClientConnection: SocketException while handling socket: " + e.getMessage());
} catch (IOException e) {
throw new UncheckedIOException(e);
} catch (InterruptedException e) {
System.out.println("Client Connection was interrupted!");
e.printStackTrace();
} finally {
if (clientSocket != null && !clientSocket.isClosed()) {
try {
clientSocket.close();
} catch (IOException ignored) {}
}
}
}
}
I do have a parent thread which is responsible for starting and managing all the ClientConnection runnables:
#Override
public void run() {
clientConnectionExecutor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
while (true) {
Socket clientSocket;
try {
// wait for a Client to connect
clientSocket = serverSocket.accept();
ClientConnection clientConnection = new ClientConnection(clientSocket, messagesQueue);
clientConnectionExecutor.execute(clientConnection);
} catch (IOException e) {
// when this exception occurs, it means that we want to shut down everything
clientConnectionExecutor.shutdownNow(); // force terminate all ClientConnections
return;
}
}
}
Now according to this Stackoverflow Question, I would have expected that as soon as shutdownNow(); is being called, an InterruptedException would be thrown within my ClientConnection.run() method, and there, it should print Client Connection was interrupted!. But this does not happen, so the catch clause seems never to be reached, the input reading loop just goes on.
I read in another Stackoverflow question that this might be related to some other codeline within the block seems to be consuming the InterruptedException, but there wasn't any particular information on what codeline could do that. So I am thankful for any hints.
Edit: It turns out that as soon as I manually exit the loop by typing "quit" on the client, the loop will quit and then, Client Connection was interrupted! will be printed. So somehow the exception seems to be ignored as long as the loop is running, and only handled afterwards.
From Oracle docs for shutdownNow:
There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.
If you take a look into ThreadPoolExecutor sources, you will find out that shutdownNow interrupts threads with this code:
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
Your ClientConnection doesn't check the flag Thread.interrupted. Due to information in the post, I can't figure out which method throws InterruptedException. Probably, some other method, for example, readLine of reader or writer, blocks the thread, because they use socket's InputStream and OutputStream and because it's obvious that socket's streams block the thread if data is not immediatly available.
For example, I wrote this code to test it:
class Example {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try(ServerSocket serverSocket = new ServerSocket()) {
serverSocket.bind(new InetSocketAddress(8080));
Socket socket = serverSocket.accept();
int dataByte = socket.getInputStream().read();
System.out.println(dataByte);
} catch (IOException e) {
e.printStackTrace();
}
});
thread.start();
thread.interrupt();
}
}
On OpenJdk-16.0.2 there is no actual interruption.
I see two possible solutions for your problem:
Check Thread.interrupted inside the while loop if you are sure that Socket doesn't block your thread.
If your are not sure, use SocketChannel in non-blocking mode instead of Socket for checking Thread.interrupted manually.
For the second way I tranformed my example into this:
class Example {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try(ServerSocketChannel serverSocket = ServerSocketChannel.open()) {
serverSocket.configureBlocking(false);
serverSocket.bind(new InetSocketAddress(8080));
SocketChannel socket = null;
while (socket == null) {
socket = serverSocket.accept();
if (Thread.interrupted()) {
throw new InterruptedException();
}
}
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
socket.read(byteBuffer);
byte[] bytes = new byte[byteBuffer.limit()];
byteBuffer.flip();
byteBuffer.get(bytes);
System.out.println(new String(bytes, StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
System.out.println("Interrupted successfully");
}
});
thread.start();
thread.interrupt();
}
}
It works.
Good luck with Java :)
I would have expected that as soon as shutdownNow(); is being called, an InterruptedException would be thrown within my ClientConnection.run()
Your messagesQueue should be a BlockingQueue. So messagesQueue.put(message) will make you need to catch an Interrupted exception. So only when the thread is blocked in the put method(queue is full), you call threadpool#shutdownNow, then the thread will receive an Interrupted exception. In other cases, thread will not receive this Interrupted exception.
You can change while ((request = reader.readLine()) != null) to while ((request = reader.readLine()) != null && !Thread.interrupted()).
Another solution is to maintain all client sockets, and close all client sockets when you need to close them, this way, the client thread will directly receive an IOException:
List<Socket> clientSockets = new ArrayList<>();
while (true) {
try {
Socket accept = serverSocket.accept();
clientSockets.add(accept);
executorService.submit(new ClientConnection(accept));
}catch (Exception e) {
for (Socket socket : clientSockets) {
try {
socket.close();
} catch (Exception exception) {
//
}
}
//executorService.shutdownNow();
}
}

Peer-to-peer chat not receiving/sending messages

I am trying to create peers that are connected to each other and are able to send/receive messages to everyone that they are connected to concurrently. They are all run on the same machine. Once connecting to a peer and acquiring a socket connection, I am starting two threads, one that is reading and one that is writing. However, readLine() blocks indefinitely and I am not sure where the problem exists. The peers successfully connect to each other, but the message exchange fails. Interrupting one peer causes a "null" message to be read from the other peers connected to it.
EDIT: Using autoflush = true in PrintWriter throws "ConnectionReset" exception to the other peers connected to the interrupted peer.
I have tried waiting for the reading thread to start before sending the message, getting the socket connection from either end of the peers, storing the input/output streams in lists stored as member variables and also just passing only the socket/all streams to each thread. Also tried different ways of reading, shown in comments in the reading thread.
class ConnectionListener extends Thread{
public void run(){
try {
while (!allPeersJoined()) {
Socket socket = null;
socket = peerServer.accept();
new PeerReader(socket).start();
new PeerWriter(socket).start();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
}
class PeerWriter extends Thread{
PrintWriter writer;
public PeerWriter(Socket socket){
try {
this.writer = new PrintWriter(socket.getOutputStream(), true);
}catch (IOException e){
e.printStackTrace();
}
}
#Override
public void run() {
writer.println("Hello");
}
}
class PeerReader extends Thread{
BufferedReader reader;
public PeerReader(Socket socket){
try {
this.reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}catch (IOException e){
e.printStackTrace();
}
}
#Override
public void run() {
String input = "";
System.out.println("Waiting to receive messages...");
try {
System.out.println(reader.readLine());
// while((input = reader.readLine()) != null){
// System.out.println(input);
// }
}catch (IOException e){
e.printStackTrace();
}
}
}
EDIT: Adding socket creation
Thread t = new ConnectionListener();
t.start();
// Connect to all peers
for (String peer : peers) {
new Socket("127.0.0.1", Integer.valueOf(peer));
}
You are creating multiple socket but then never use them.
Right now the ConnectionListener get your connection, send the bytes on the connected sockets, but the sockets never responds ... because you never told them to.
You should in the same way you did with ConnectionListener, create an object called
ClientConnection, that has its own writer and reader.

How to synchronize closing socket by two threads?

I have two threads, one for reading, one for writing data through the same socket. When is problem with connection two threads catch exceptions and try reconnect.To do this they call the same methods
public synchronized void close_connection() {
try {
socket.shutdownInput();
socket.shutdownOutput();
socket.close();
try {
Thread.sleep(500);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
and after it second one to try establish connection:
public synchronized boolean connect() {
boolean result=true;
socket = new Socket();
try {
socket.connect(new InetSocketAddress(address, port), 500);
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
out = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()));
} catch (IOException e) {
result=false;
}
return result;
}
The problem is how to avoid trying connect with server from two threads one by one immediatly (after connection error - for example afrter closing connection by server). I mean: if one thread tries do connection the second thread should know this and dosen't try do the same but wait for establish connection by first one (to avoid permanent fight threads problem disconnect,connect, disconnect, connect....). I've tried with synchronization but my experience is too small.
Regards,
Artik
You could try something like this:
while(not connected){
try reconnecting
if(success){
//Everything is ok, go on
} else {
//sleep for random period of time and retry
}
}
or you can implement the socket operations in an object and share that object between your threads using locks.
Use appropriate mutex locking. This will make sure only one thread will access the connect() portion of your code.

Multiple clients - server in java

I'm using socket to writing multiple clients - server application in java. I wrote simple client - server application and everything was ok but when i tried change it to multi clients app I got the exception when i started client:
Exception in thread "pool-1-thread-1" java.lang.NullPointerException
at MiniSerwer.run(Serwer.java:110)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:679)
I have two more classes (threads - InWorker and OutWorker to input and output).
Serwer.java (without InWorker and OutWorker) :
public class Serwer {
Serwer(int port) {
ServerSocket serversocket=null;
ExecutorService exec= Executors.newCachedThreadPool();
try {
serversocket=new ServerSocket(port);
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
Socket socket=null;
try {
socket = serversocket.accept();
} catch (IOException e) {
e.printStackTrace();
}
exec.execute(new MiniSerwer(socket)); // create new thread
}
} }
MiniSerwer - helper class to create owns thread to everyone client
class MiniSerwer implements Runnable{
Socket socket=null;
ExecutorService exec=null;
ObjectOutputStream oos=null;
ObjectInputStream ois=null;
MiniSerwer(Socket socket) {
this.socket=socket;
try {
oos=new ObjectOutputStream(socket.getOutputStream());
oos.flush();
ois=new ObjectInputStream(socket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while(true) {
exec.execute(new InWorker(socket, ois)); // input stream
exec.execute(new OutWorker(socket, oos)); //output stream
Thread.yield();
}
}
}
I change my program but it still doesn't work. Any other suggestion ?
Server:
public class Serwer implements Runnable{
ServerSocket serversocket=null;
ExecutorService exec= Executors.newCachedThreadPool();
int port;
Serwer(int port) {
this.port=port;
}
public void run() {
try {
serversocket=new ServerSocket(port);
while(true) {
Socket socket=null;
try {
socket = serversocket.accept();
exec.execute(new MiniSerwer(socket)); // create new thread
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
int port;
Scanner in = new Scanner(System.in);
System.out.println("Enter the port:");
port = in.nextInt();
ExecutorService exec=Executors.newCachedThreadPool();
exec.execute(new Serwer(port));
}
}
MiniSerwer:
class MiniSerwer implements Runnable{
Socket socket=null;
ExecutorService exec=Executors.newCachedThreadPool();
ObjectOutputStream oos=null;
ObjectInputStream ois=null;
MiniSerwer(Socket socket) {
this.socket=socket;
}
public void run() {
try {
oos=new ObjectOutputStream(socket.getOutputStream());
oos.flush();
ois=new ObjectInputStream(socket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
exec.execute(new InWorker(socket, ois)); // input stream
exec.execute(new OutWorker(socket, oos)); //output stream
Thread.yield();
}
}
}
I have a lot of exceptions when I'm trying send message from client to server.
2 sec. after connecting on the server side (i don't send anything) :
Exception in thread "pool-2-thread-1" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:657)
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:943)
at java.util.concurrent.ThreadPoolExecutor.processWorkerExit(ThreadPoolExecutor.java:992)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:679)
Your executor service, in your MiniSerwer class, is never initialized. That's the root cause of your NPE.
But like I mentioned in my comment, you should not be doing all the Serwer logic in it's constructor. The object never gets fully initialized because you never exit the constructor. Make the entire class Runnable and move that logic to the overridden run method. Then add a main method to be used in actually instantiation/running the server.
Also, in your MiniSerwer, your stream initialization can fail. You need to validate the streams aren't null before using them in the run method. Or just move the initialization logic for them to the beginning of your run method.
EDIT
You also have a bug in your MiniSerwer implementation, you spawn an infinite number of threads to process the object input and output streams:
while(true) {
exec.execute(new InWorker(socket, ois)); // input stream
exec.execute(new OutWorker(socket, oos)); //output stream
Thread.yield();
}
You will either run out of threads, run out of memory, or both. To be honest, your solution is over-engineered, I doubt the In and Out workers really need to be separated the way you have them now.
Never do such terrible things. In the code below you ignored exception twice:
First ignore:
try {
serversocket=new ServerSocket(port);
} catch (IOException e) {
e.printStackTrace();
}
after that serversocket could be null as before
and second ignore:
while(true) {
Socket socket=null;
try {
socket = serversocket.accept();
} catch (IOException e) {
e.printStackTrace();
}
exec.execute(new MiniSerwer(socket)); // create new thread
}
after that try...catch socket also could be null as before.
Both things could lead to the NullPointerException !
Fix it all like:
try {
serversocket=new ServerSocket(port);
while(true) {
Socket socket=null;
try {
socket = serversocket.accept();
exec.execute(new MiniSerwer(socket)); // create new thread
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
} catch (IOException e) {
e.printStackTrace();
}
UPD: This one: while(true) {...} is also terrible thing. But let's left this after the brackets of this question.

How to determine if server closed connection (RST packet received) in Java?

I'm using Socket class for my TCP connection. But my current problem is to determine exactly disconnect reason.
In both cases (if there's connection timeout or server closed connection) I receive SocketException with "Broken pipe" message. So how I can exactly determine disconnect reason?
Thanks!
I think you should get a different Exception thrown. If you are talking about a connection then you should get a SocketException from a host which sends a reset (I think that's the RST packet) and a SocketTimeoutException if your connection times out.
If you are talking about IO then again, if the server drops the connection you will get a SocketException while if the IO times out (maybe just the read) you will get a SocketTimeoutException.
Here's the test program I used. Of course I'm bleeding sockets like crazy.
try {
new Socket().connect(new InetSocketAddress(someIpThatHangs, 8000), 1000);
fail("Should have thrown");
} catch (SocketTimeoutException e) {
// we expected it to timeout
}
try {
new Socket().connect(new InetSocketAddress(someIpThatResets, 1000));
fail("Should have thrown");
} catch (SocketException e) {
// we expected it to throw an exception immediately on reset
}
// start our server
final ServerSocket serverSocket = new ServerSocket();
int serverPort = 8000;
InetSocketAddress address = new InetSocketAddress("127.0.0.1", serverPort);
serverSocket.bind(address);
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Socket clientSocket = serverSocket.accept();
System.err.println("Got a connection");
Thread.sleep(1000);
clientSocket.close();
} catch (InterruptedException e) {
return;
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
});
thread.start();
// wait for the server to start
Thread.sleep(100);
Socket clientSocket = new Socket();
clientSocket.connect(address);
try {
// read until the server closes the connection
clientSocket.getInputStream().read();
} catch (SocketException e) {
// expected socket exception
}
clientSocket = new Socket();
clientSocket.connect(address);
clientSocket.setSoTimeout(100);
try {
// read until the socket timeout expires
clientSocket.getInputStream().read();
} catch (SocketTimeoutException e) {
// expected read timeout exception
}
serverSocket.close();
thread.interrupt();

Categories

Resources