Java 如何在客户机-服务器多线程中停止服务器
我正在用java实现一个多线程的客户机-服务器应用程序。我想在这个程序中实现JDBC,我想让服务器在启动时从数据库中检索数据。我将把这些数据存储在我的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
集合
实例中,对数据执行操作,当服务器完成执行时,我需要将数据存储回数据库。问题是服务器在无限循环中等待客户机,我不知道如何使服务器停止
这是我的服务器程序:
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 forSocketExceptions
并测试是否使用了毒药丸;如果是,则让我们清理,如果不是,则让错误处理
超时
您还可以在
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