A multi-threaded Java server * sometimes * throws a SocketException (Socket is closed) in the ServerSocket.accept () method

I have been investigating this problem for hours and hours, and I cannot come up with a decent solution or explanation of why this exception (java.net.SocketException: Socket closed) is being thrown. My last approach is now to ask you guys.

I created a simple client-server application for testing (for example, a “real” application uses the same logic), see below.

If I repeat calling the same test script (for example, via the TestNG invocationcount annotation parameter or using a simple for loop), at some point there will be java.net.SocketException: Socket closed .

The following test case just starts the server (opens the server socket), waits a couple of milliseconds, and then closes the socket again. Closing the server socket involves opening the socket so that the server returns from the ServerSocket.accept () method (see "Shutting down the server" ()).

Perhaps this is a multithreading issue with the code immediately after ServerSocket.accept () - line. Therefore, I temporarily surrounded him with a synchronized block - also did not help.

Do you have an idea why this exception gets?

Best Chris

Server.java is as follows:

package multithreading;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import org.apache.log4j.Logger;

public class Server {

private ServerSocket serverSocket;
private boolean isShuttingDown;
private final static Logger logger = Logger.getLogger(Server.class);

public void start() throws Exception {
    try {
        serverSocket = new ServerSocket(5000);
        isShuttingDown = false;
    } catch (Exception e) {
        throw new RuntimeException("Starting up the server failed - aborting", e);
    }

    while (true) {
        try {
            Socket socket = serverSocket.accept();

            if (!isShuttingDown) {
                new Thread(new EchoRequestHandler(socket)).start();
            } else {
                logger.info("Server is going to shutdown");
                break;
            }
        } catch (IOException e) {
            logger.error("Error occured while waiting for new connections, stopping server", e);
            throw e;
        }
    }
}

public synchronized boolean isRunning() {
    if (serverSocket != null && serverSocket.isBound() && !serverSocket.isClosed() && !isShuttingDown) {
        return true;
    }
    return false;
}

public synchronized void shutdown() throws IOException {
    if (isRunning()) {
        isShuttingDown = true;
        if (serverSocket != null && !serverSocket.isClosed()) {
            try {
                /*
                 * since the server socket is still waiting in it accept()
                 * method, just closing the server socket would cause an
                 * exception to be thrown. By quickly opening a socket
                 * (connection) to the server socket and immediately closing
                 * it again, the server socket accept method will return
                 * and since the isShuttingDown flag is then false, the
                 * socket will be closed.
                 */
                new Socket(serverSocket.getInetAddress(), serverSocket.getLocalPort()).close();

                serverSocket.close();
            } catch (IOException e) {
                logger.error("Closing the server socket has failed - aborting now.", e);
                throw e;
            }
        }
    } else {
        throw new IOException("Server socket is already closed which should not be the case.");
    }
}
}

The test class does the following:

package multithreading;

import java.io.IOException;

import org.testng.annotations.Test;

public class Testing {

// @Test(invocationCount=10, skipFailedInvocations=true)
@Test
public void loadTest() throws InterruptedException, IOException {
    for (int i = 0; i < 10; i++) {
        final Server s = new Server();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    s.start();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        }).start();
        Thread.sleep(500);
        gracefullyShutdownServer(s);
        Thread.sleep(1000);
    }
}

private void gracefullyShutdownServer(final Server server) throws InterruptedException {
    try {
        server.shutdown();
        while (server.isRunning()) {
            Thread.sleep(500);
        }
    } catch (IOException e) {
        System.err.println(e);
    }
}

}

The stack trace is as follows:

ERROR 2011-03-13 16:14:23,537 [Thread-6] multithreading.Server: Error occured while waiting for new connections, stopping server
java.net.SocketException: Socket closed
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:390)
at java.net.ServerSocket.implAccept(ServerSocket.java:453)
at java.net.ServerSocket.accept(ServerSocket.java:421)
at multithreading.Server.start(Server.java:26)
at multithreading.Testing$1.run(Testing.java:18)
at java.lang.Thread.run(Thread.java:680)
java.net.SocketException: Socket closed
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:390)
at java.net.ServerSocket.implAccept(ServerSocket.java:453)
at java.net.ServerSocket.accept(ServerSocket.java:421)
at multithreading.Server.start(Server.java:26)
at multithreading.Testing$1.run(Testing.java:18)
at java.lang.Thread.run(Thread.java:680)
+3
source share
2 answers

JN is right about how you should handle closing.

, , , , isShuttingDown . , . , .

, J.N. : . , , , close , isShuttingDown, , . ( synchronized (this) {}, .)

, isShuttingDown volatile, developerWorks Java: . , .

+5

javadoc, - . "" , , .

+4

All Articles