Minimal Reproducible Example
Server.java
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.ServerSocket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(12345, 3);
Socket socket = serverSocket.accept(); // incoming request
new WorkerThread(socket).start();
}
}
class WorkerThread extends Thread {
private Socket socket;
public WorkerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.flush();
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); // line 28
// handle the request using oos and ois
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client.java
import java.net.Socket;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class Client {
public static void main(String[] args) throws Exception {
try (Socket socket = new Socket("192.168.1.3", 12345)) {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.flush();
// ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); // line 11
// send some data only using oos
}
}
}
Thrown Exception
java.net.SocketException: An established connection was aborted by the software in your host machine
at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:325)
at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
at java.base/java.net.Socket$SocketInputStream.read(Socket.java:966)
at java.base/java.io.ObjectInputStream$PeekInputStream.read(ObjectInputStream.java:2908)
at java.base/java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2924)
at java.base/java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:3421)
at java.base/java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:959)
at java.base/java.io.ObjectInputStream.<init>(ObjectInputStream.java:397)
at WorkerThread.run(Server.java:28)
The WorkerThread
seems to be causing the issue, since the SocketException
is not thrown if the code in the code of the WorkerThread#run
method is placed in the Server#main
method. See Note below.
The intent here is to have a separate Thread (other than the main Thread of the Server) handle each request as it comes, therefore the WorkerThread
receives a reference to the Socket
associated with the incoming connection.
The WorkerThread
needs to open both oos
and ois
(even though they might not be both strictly needed for communication) because opening only the ois
won't work. Further reading on why this happens.
What is the underlying cause of this issue? Is there a way to fix the problem other than the hacky (?) solution presented below?
Note
Running the above Client with this Server does not throw the Exception:
NonThreadedServer.java
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.ServerSocket;
public class NonThreadedServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(12345, 3);
Socket socket = serverSocket.accept(); // incoming request
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.flush();
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
// handle the request using oos and ois
} catch (IOException e) {
e.printStackTrace();
}
}
}