0

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();
        }
    }
}
Alex Mandelias
  • 436
  • 5
  • 10

1 Answers1

1

Solution

Uncomment line 11 of Client, i.e. create an ObjectInputStream, even though it is not strictly needed for the communication:

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
        }
    }
}

As mentioned in the question, I don't know what the underlying issue is or whether this solution is the correct one. If it isn't, I'll make sure to mark another answer as the accepted one.

Alex Mandelias
  • 436
  • 5
  • 10