Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/343.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在客户机-服务器多线程中停止服务器_Java_Multithreading_Server_Client - Fatal编程技术网

Java 如何在客户机-服务器多线程中停止服务器

Java 如何在客户机-服务器多线程中停止服务器,java,multithreading,server,client,Java,Multithreading,Server,Client,我正在用java实现一个多线程的客户机-服务器应用程序。我想在这个程序中实现JDBC,我想让服务器在启动时从数据库中检索数据。我将把这些数据存储在我的集合实例中,对数据执行操作,当服务器完成执行时,我需要将数据存储回数据库。问题是服务器在无限循环中等待客户机,我不知道如何使服务器停止 这是我的服务器程序: import java.io.*; import java.text.*; import java.util.*; import java.net.*; public class Serve

我正在用java实现一个多线程的客户机-服务器应用程序。我想在这个程序中实现JDBC,我想让服务器在启动时从数据库中检索数据。我将把这些数据存储在我的
集合
实例中,对数据执行操作,当服务器完成执行时,我需要将数据存储回数据库。问题是服务器在无限循环中等待客户机,我不知道如何使服务器停止

这是我的服务器程序:

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

    @Override
    public void run() 
    {
        String received;
        String toreturn;
        while (true) {
            try {
                // Ask user what he wants
                dos.writeUTF("What do you want?[Date | Time]..\n"+
                        "Type Exit to terminate connection.");

                // receive the answer from client
                received = dis.readUTF();

                if(received.equals("Exit"))
                { 
                    System.out.println("Client " + this.s + " sends exit...");
                    System.out.println("Closing this connection.");
                    this.s.close();
                    System.out.println("Connection closed");
                    break;
                }

                // creating Date object
                Date date = new Date();

                // write on output stream based on the
                // answer from the client
                switch (received) {         
                    case "Date" :
                        toreturn = fordate.format(date);
                        dos.writeUTF(toreturn);
                        break;

                    case "Time" :
                        toreturn = fortime.format(date);
                        dos.writeUTF(toreturn);
                        break;

                    default:
                        dos.writeUTF("Invalid input");
                        break;
                }
            } 
            catch (IOException e) {
                e.printStackTrace();
            }
        }

        try
        {
            // closing resources
            this.dis.close();
            this.dos.close();            
        }
        catch(IOException e){
            e.printStackTrace();
        }
    }
}
这是我的客户程序:

import java.io.*;
import java.net.*;
import java.util.Scanner;

// Client class
public class Client 
{
    public static void main(String[] args) throws IOException 
    {
        try
        {
            Scanner scn = new Scanner(System.in);

            // getting localhost ip
            InetAddress ip = InetAddress.getByName("localhost");

            // establish the connection with server port 5056
            Socket s = new Socket(ip, 5056);

            // obtaining input and out streams
            DataInputStream dis = new DataInputStream(s.getInputStream());
            DataOutputStream dos = new DataOutputStream(s.getOutputStream());

            // the following loop performs the exchange of
            // information between client and client handler
            while (true) 
            {
                System.out.println(dis.readUTF());
                String tosend = scn.nextLine();
                dos.writeUTF(tosend);

                // If client sends exit,close this connection 
                // and then break from the while loop
                if(tosend.equals("Exit"))
                {
                    System.out.println("Closing this connection : " + s);
                    s.close();
                    System.out.println("Connection closed");
                    break;
                }

                // printing date or time as requested by client
                String received = dis.readUTF();
                System.out.println(received);
            }

            // closing resources
            scn.close();
            dis.close();
            dos.close();
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
}
您可以与volatile布尔变量一起使用,并且应该将其置于“while”中—当处理完成时,将其设置为false,服务器将停止

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

您可以使用volatile boolean变量,并应将其放置在“while”中-当处理完成时,将其设置为false,服务器将停止


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

概述

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

ExecutorServer

我将根据示例运行一个经过修改的示例。下面是服务器实现

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

一种执行器,提供管理终止的方法,以及可以生成未来跟踪一个或多个异步任务进度的方法

通过将ClientHandler分派到
执行器服务
,您正在使用
线程池
。尽管这带来了很多好处,但最重要的是您可以更好地控制多线程服务,
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方法

毒丸

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

超时


您还可以在
ServerSocket
上设置一个超时,这样每当它在该时间间隔内无法与
myServer.setSoTimeout(2000)建立连接时,它都会抛出一个异常。这将引发一个
中断异常
,处理方法与毒药丸类似,在毒药丸中通过CLI命令更改标志,并检查是否应在catch块中退出。如果它应该退出,让我们清理,如果不是,让我们处理错误。

概述

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

ExecutorServer

我将根据示例运行一个经过修改的示例。下面是服务器实现

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

一种执行器,提供管理终止的方法,以及可以生成未来跟踪一个或多个异步任务进度的方法

通过将ClientHandler分派到
执行器服务
,您正在使用
线程池
。尽管这带来了很多好处,但最重要的是您可以更好地控制多线程服务,
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方法

毒丸

如果实现一个处理来自CLI的所有传入命令的
new Thread()
,则该线程将充当毒药。这个想法是把一颗毒药送到t