Christian Eriksson Christian Eriksson - 1 year ago 52
Java Question

Why does my connection reset first time I try to write to Socket?

When I run my fairly simple TCP Server I notice that the first time I try to connect and send an object I get a connection reset error. If I keep the server running but let the client send again it all works. I'am at a loss here, what causes this behaviour?

Client:

for (int i = 0; i < 3; i++) {
Socket s = new Socket("192.168.0.10", 9750);
SysIO.print("Connected: " + s.isConnected());
ObjectOutputStream oos = new ObjectOutputStream(
new BufferedOutputStream(s.getOutputStream()));
Object obj = new OneMessage("Hi there: " + i);
oos.writeObject(obj);
oos.flush();

sleep(1000); // <-- turns error on and off :/
}


Server:

try (ServerSocket incomingSocket = new ServerSocket(mPort)) {
SysIO.print("Game Server started...");
incomingSocket.setSoTimeout(mTimeout);

while (mRunning) {
Socket clientConnection = null;
try {
clientConnection = incomingSocket.accept();
clientConnection.setSoTimeout(3000);

final Socket connection = clientConnection;
Thread requestHandlingThread = new Thread(() -> {
mRequestHandler.handleRequest(connection);
});
requestHandlingThread.start();

} catch (SocketTimeoutException ste) {
SysIO.print("TCP timeout...");
} catch (IOException ex) {
Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
} catch (BindException ex) {
SysIO.print("Could not bind: " + ex.getMessage());
} catch (IOException ex) {
SysIO.print("There was a problem with IO in TCP Server: " + ex.getMessage());
Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null, ex);
}


Request Handler:

public void handleRequest(Socket aRequest) {

try {
SysIO.print("Connected: " + aRequest.isConnected());
ObjectInputStream ois = new ObjectInputStream(
new BufferedInputStream(aRequest.getInputStream()));
GameMessage message = (GameMessage) ois.readObject();

aRequest.close();


SysIO.print("Received: " + message.getType());
} catch (IOException | ClassNotFoundException ex) {
SysIO.print("IO exception: " + ex.getMessage());
Logger.getLogger(SimpleHandler.class.getName()).log(Level.SEVERE, null, ex);
}

}


I've tried closing and not closing the socket from the server after each request.

If I run the client without a loop it will seem to work, I thought it failed at first but I couldn't recreate it.

If I try to run the client in a loop all connections will fail the first time I run the client but if I then restart the client all will succeed.

Putting a sleep(1000) to pause a loop like above will make all connections succeed. Is it that simple that the Server can't handle quick connection attempts? I was hoping putting the request handling in separate threads would enable this. But why would the first connection in the loop also fail?

Regards,
Christian

Answer Source

So in the end I eneded up with something like this:

Client:

try {
    Socket connection = new Socket(mHostAddress, mHostPort);
    connection.setSoTimeout(mTimeOut);
    ObjectOutputStream outgoing = new ObjectOutputStream(
            new BufferedOutputStream(connection.getOutputStream()
            )); // <-- Opening output stream first in client (opposite to server)
    outgoing.writeObject(mMessage);
    outgoing.flush();
    outgoing.close(); // <-- closing the stream as per EJP's comment
} catch (IOException ex) {
    System.out.print("IOException in TCPSender: " + ex.getMessage());
}

Server:

ExecutorService pool = Executors.newFixedThreadPool(mClientThreads);
try (ServerSocket server = new ServerSocket(mPort)) {
    while (mRunning) {
        final Socket client = server.accept();
        client.setSoTimeout(mTimeOut);
        pool.execute(() -> {
            mMessageHandler.handle(client); // mMessageHandler = NetworkMessageHandler
        });
    }
} catch (IOException ex) {
    System.out.println("IO Exception occurred in TCPServer: "
            + ex.getMessage());
} finally {
    System.out.println("Server stopped...");
}

NetworkMessageHandler

try {
    ObjectInputStream input = new ObjectInputStream(
            new BufferedInputStream(aClient.getInputStream()) // Input first in server
    );
    NetworkMessage message = (NetworkMessage) input.readObject();
    input.close(); // <-- closing stream
    aClient.close(); // <-- making sure to close the Socket connection to client

    act(message, sendersIP); <-- acting on the message from client

} catch (IOException ex) {
    System.out.println("An IO exception occurred "
            + "in NetworkMessageHandler: " + ex.getMessage());
} catch (ClassNotFoundException ex) {
    System.out.println("Could not recreate the sent class: "
            + ex.getMessage());
}

I made sure that I didn't miss to close my streams and sockets and followed this oracle tutorial for someextra hints.

Regards, Christian