为了账号安全,请及时绑定邮箱和手机立即绑定

如何在客户端服务器多线程中停止服务器

如何在客户端服务器多线程中停止服务器

犯罪嫌疑人X 2021-09-03 13:03:09
我正在用 java 实现一个多线程客户端-服务器应用程序。我想在这个程序中实现JDBC,我希望我的服务器在启动时从数据库中检索数据。我会将这些数据存储在我的collection实例中,对数据执行操作,当服务器完成执行时,我需要将数据存储回数据库。问题是服务器处于无限循环等待客户端,我无法弄清楚如何让服务器停止。这是我的服务器程序:import java.io.*;import java.text.*;import java.util.*;import java.net.*;public class Server {    public static void main(String[] args) throws IOException     {        // server is listening on port 5056        ServerSocket ss = new ServerSocket(5056);        // running infinite loop for getting        // client request        while (true)         {            Socket s = null;            try {                // socket object to receive incoming client requests                s = ss.accept();                System.out.println("A new client is connected : " + s);                // obtaining input and out streams                DataInputStream dis = new DataInputStream(s.getInputStream());                DataOutputStream dos = new DataOutputStream(s.getOutputStream());                System.out.println("Assigning new thread for this client");                // create a new thread object                Thread t = new ClientHandler(s, dis, dos);                // Invoking the start() method                t.start();            }            catch (Exception e) {                s.close();                e.printStackTrace();            }        }    }}// ClientHandler classclass ClientHandler extends Thread {    DateFormat fordate = new SimpleDateFormat("yyyy/MM/dd");    DateFormat fortime = new SimpleDateFormat("hh:mm:ss");    final DataInputStream dis;    final DataOutputStream dos;    final Socket s;    // Constructor    public ClientHandler(Socket s, DataInputStream dis, DataOutputStream dos)     {        this.s = s;        this.dis = dis;        this.dos = dos;    }
查看完整描述

2 回答

?
收到一只叮咚

TA贡献1821条经验 获得超4个赞

概述


好问题!重申上述评论中所述的内容,您正在寻找服务器端关闭。有一些方法可以处理这种情况,我可以用一个简短的例子来解释它。


执行服务器


我将根据这个例子运行一个修改过的例子。下面找到服务器实现。


class NetworkService implements Runnable {

    private final ServerSocket serverSocket;

    private final ExecutorService pool;

    private final AtomicBoolean shouldExit;


    public NetworkService(int port, int poolSize) throws IOException {

        serverSocket = new ServerSocket(port);

        pool = Executors.newFixedThreadPool(poolSize);

        shouldExit = new AtomicBoolean(false); // Thread-safe boolean

    }


    public void run() { // run the service

        try {


           // While we should not exit

           while(!shouldExit.get()) {

             try {

                 pool.execute(new ClientHandler(serverSocket.accept()));

             } catch (SocketException e) {

                 if(shouldExit.get()) break; // Poison pill has been delivered, lets stop

                 // Error handling

             }

           }

        } catch (IOException ex) {

           pool.shutdown();

        }


       // Clean up the thread pool

       shutdownAndAwaitTermination();

    }

}


class ClientHandler implements Runnable {

    private final Socket socket;

    ClientHandler (Socket socket) { this.socket = socket; }

    public void run() {

        ...

    }

    ...

 }

在这里,您将修改当前的服务器代码以恐吓此结构。您目前有类似的妆容,但我们在这里添加了ExecutorService.


一个 Executor 提供管理终止的方法和可以生成 Future 以跟踪一个或多个异步任务的进度的方法。


通过将您的 ClientHandler 分派到ExecutorService,您正在使用ThreadPool. 虽然这带来了很多好处,但最重要的是您可以更好地控制多线程服务,ThreadPool管理线程利用率,并且应用程序效率将大大提高。


以下是您尝试关闭和终止所有剩余线程的方法:


void shutdownAndAwaitTermination(ExecutorService pool) {

    pool.shutdown(); // Disable new tasks from being submitted

    try {

        // Wait a while for existing tasks to terminate

        if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {

            pool.shutdownNow(); // Cancel currently executing tasks

            // Wait a while for tasks to respond to being cancelled

        if (!pool.awaitTermination(60, TimeUnit.SECONDS))

            System.err.println("Pool did not terminate");

        }

    } catch (InterruptedException ie) {

        // (Re-)Cancel if current thread also interrupted

        pool.shutdownNow();

        // Preserve interrupt status

        Thread.currentThread().interrupt();

    }

}

现在,问题仍然是我们如何关闭服务器?上面的代码显示了一个改进的结构,但仍然存在阻塞的问题serverSocket.accept()!


解决方案


想到这个场景时,有两个想法浮现在脑海中;CLI 或 GUI。两者具有相同的语义,最终由您决定。出于解释的目的,我将参考 CLI 方法。


毒丸


如果您实现new Thread()处理来自 CLI 的所有传入命令,则该线程将充当毒丸。这个想法是向目标递送毒丸,使其可以醒来/执行并死亡。该线程会将shouldExit原子布尔值更改为true并创建一个new Socket(serverSocket.getInetAddress(), serverSocket.getLocalPort()).close();以连接到ServerSocket并立即关闭它。在上面的代码中,应用程序将不再阻塞serverSocket.accept(). 相反,它将进入 try catchSocketExceptions并测试是否使用了毒丸;如果是,那么让我们清理,如果不是,让错误处理。


暂停


您还可以在 上设置超时,ServerSocket以便每次在该时间间隔内无法与myServer.setSoTimeout(2000);. 这将抛出一个InterruptedIOException并且 可以类似于毒丸处理,通过 CLI 命令更改标志并检查它是否应该在 catch 块中退出。如果它应该退出,让我们清理,否则让错误处理。


查看完整回答
反对 回复 2021-09-03
?
九州编程

TA贡献1785条经验 获得超4个赞

您可以将模式标志与 volatile 布尔变量一起使用,并且您应该将它放在 'while' 中 - 当处理完成时,将其设置为 false 并且服务器将停止。

另一种方法 - 使用线程池并等待它们在服务器的主线程中完成。


查看完整回答
反对 回复 2021-09-03
  • 2 回答
  • 0 关注
  • 201 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信