消息 Java 关闭多线程套接字服务器

Multi thread socket server shutdown by message Java

我有一个多线程进程来侦听消息并处理它们。如果收到的消息之一是 "shutdown",我希望能够关闭进程。除了关机部分我都实现了。

我有一个 "Multi" class,它使用 start 方法扩展了 java.net.ServerSocket。里面...

java.net.Socket socket = null;
while (true) {
            try {
                socket = this.accept();
                new Thread(new SocketThread(socket, verifier, threading)).start();

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

SocketThread 是 implements Runnable 的另一个 class。有什么方法可以使它工作吗?

我以前不必这样做(因为我通常不会发现自己需要编写太多原始 SocketServer),但是对于这种类型的线程协调,我会尝试类似以下的操作...

public class App {
    public static void main(String[] args) {
        new App().run();
    }

    public void run() {
        try {
            System.out.println("Starting...");
            AtomicBoolean running = new AtomicBoolean(true);
            Collection<Socket> sockets = new ArrayList<>();
            Collection<Thread> threads = new ArrayList<>();
            try (ServerSocket socketServer = new ServerSocket(10101)) {
                System.out.println("Started.");
                while (running.get()) {
                    Socket socket = socketServer.accept();
                    sockets.add(socket);
                    if (running.get()) {
                        Thread thread = new Thread(new SocketHandler(socket, running));
                        thread.start();
                        threads.add(thread);
                    }
                }
                System.out.println("Stopping...");
                sockets.forEach(socket -> {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });
                threads.forEach(thread -> {
                    try {
                        thread.join();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
            }
            System.out.println("Stopped.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static class SocketHandler implements Runnable {
        private final Socket socket;
        private final AtomicBoolean running;

        SocketHandler(Socket socket, AtomicBoolean running) {
            this.socket = socket;
            this.running = running;
        }

        @Override
        public void run() {
            try {
                System.out.println("Client connected.");
                try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
                    boolean connected = true;
                    while (connected){
                        String command = in.readLine();
                        System.out.println("Command received: " + command);
                        if (command == null) {
                            connected = false;
                        } else if (command.equals("shutdown")) {
                            running.set(false);
                            try (Socket tmpSocket = new Socket("localhost", 10101)) {}
                        }
                        // process other commands
                    }
                }
                System.out.println("Client disconnected.");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

更新:更改了示例以建立与服务器的连接以使其解锁。

更新: 处理客户端断开连接情况的示例代码。感谢 @user207421 强调这一点(谢谢)。

更新: 更改了示例代码以处理多个客户端套接字/线程。请注意,当您关闭套接字时,它将通过一个异常,该异常当前刚刚打印到 stderr。您可能希望以不同的方式处理它。

更新:您可能还会发现模拟多个客户端连接的代码很有帮助:

public class Clients {
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> new NormalClient().run());
        Thread thread2 = new Thread(() -> new NormalClient().run());
        Thread thread3 = new Thread(() -> new NormalClient().run());
        Thread thread4 = new Thread(() -> new NormalClient().run());
        Thread thread5 = new Thread(() -> new ShutdownClient().run());
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        thread5.start();
    }
}

class NormalClient {
    void run() {
        try {
            try (Socket socket = new Socket("localhost", 10101);
                 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) {

                for (int i = 0; i < 10; i++) {
                    out.write("hello " + i);
                    out.newLine();
                    out.flush();
                    sleep(1000);
                }
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class ShutdownClient {
    void run() {
        try {
            try (Socket socket = new Socket("localhost", 10101);
                 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) {

                sleep(8000);
                out.write("shutdown");
                out.newLine();
                out.flush();
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}