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();
}
}
}