教你利用JAVA实现可以自行关闭服务器的方法

网友投稿 389 2023-01-01

教你利用JAVA实现可以自行关闭服务器的方法

java实现可以自行关闭的服务器

普通实现的服务器都无法关闭自身,只有依靠操作系统来强行终止服务程序。这种强行终止服务程序的方式尽管简单方便,但会导致服务器中正在执行的任务突然中断。如果服务器处理的任务非常重要,不允许被突然中断,应该由服务器自身在恰当的时刻关闭自己

代码如下:

EchoServer类

package ShutdownServer;

import java.io.*;

import java.net.ServerSocket;

import java.net.Socket;

import java.net.SocketException;

import java.net.SocketTimeoutException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.RejectedExecutionException;http://

import java.util.concurrent.TimeUnit;

public class EchoServer {

private int port=8000;

private ServerSocket serverSocket;

private ExecutorService executorService; //线程池

private final int POOL_SIZE=4http://; //单个CPU时线程池中工作线程的数目

private int portForShutdown=8001; //用于监听关闭服务器命令的端口

private ServerSocket serverSocketShutdown;

private boolean isShutdown=false; //服务器是否已经关闭

private Thread shutdownThread=new Thread(){

//负责关闭服务器的线程

public void run(){

while(!isShutdown){

Socket socketForShutdown=null;

try{

socketForShutdown=serverSocketShutdown.accept();

BufferedReader br=new BufferedReader(

new InputStreamReader(socketForShutdown.getInputStream())

);

String command=br.readLine();

if (command.equals("shutdown")){

long beginTime=System.currentTimeMillis();

socketForShutdown.getOutputStream().write("服务器正在关闭\r\n".getBytes());

isShutdown=true;

//请求关闭线程池

//线程池不再接收新的任务,但会继续执行完工作队列中现有的任务

executorService.shutdown();

//等待关闭线程池,每次等待的超时时间为30s

//当使用awaitTermination时,主线程会处于一种等待的状态,等待线程池中所有的线程都运行完毕后才继续运行。

//如果等待的时间超过指定的时间,但是线程池中的线程运行完毕,那么awaitTermination()返回true。执行分线程已结束

//如果等待的时间超过指定的时间,但是线程池中的线程未运行完毕,那么awaitTermination()返回false。不执行分线程已结束

//如果等待时间没有超过指定时间,等待!

//可以用awaitTermination()方法来判断线程池中是否有继续运行的线程。

while(!executorService.isTerminated())

executorService.awaitTermination(30, TimeUnit.SECONDS);

//关闭与EchoClient客户通信的ServerSocket

serverSocket.close();

long endTime=System.currentTimeMillis();

socketForShutdown.getOutputStream().write(("服务器关闭,"+"关闭服务器用了"+(endTime-beginTime)+"ms\r\n").getBytes());

socketForShutdown.close();

serverSocketShutdown.close();

System.out.println("服务器关闭");

}

else {

socketForShutdown.getOutputStream().write("错误的命令\r\n".getBytes());

socketForShutdown.close();

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

};

public EchoServer() throws IOException {

serverSocket=new ServerSocket(port);

//设定等待客户连接的超时时间为60s

serverSocket.setSoTimeout(60000);

serverSocketShutdown=new ServerSocket(portForShutdown);

//创建线程池

executorService= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE);

shutdownThread.start();

System.out.println("服务器启动");

}

public void service(){

while(!isShutdown){

Socket socket=null;

try {

//可能会抛出SocketTimeoutException和SocketException

socket=serverSocket.accept();

//把等待客户发送数据的超时时间设为60s

socket.setSoTimeout(60000);

//可能会抛出RejectedExecutionException

executorService.execute(new Handler(socket));

}catch (SocketTimeoutException e){

//不必处理等待客户连接时出现的异常

}catch (RejectedExecutionException e) {

try {

if (socket != null)

socket.close();

} catch (IOException ex) {

return;

}

}catch (SocketException e){

if (e.getMessage().indexOf("socket closed")!=-1)

return;

}catch (IOException e){

e.printStackTrace();

}

}

}

public static void main(String[] args) throws IOException { //main方法抛出异常,异常直接交给虚拟机,虚拟机直接结束异常

new EchoServer().service();

}

}

//负责与单个客户通信的任务

class Handler implements Runnable{

private Socket socket;

public Handler(Socket socket){

this.socket=socket;

}

private PrintWriter getWriter(Socket socket) throws IOException{

OutputStream socketOut=socket.getOutputStream();

return new PrintWriter(socketOut,true);

}

private BufferedReader getReader(Socket socket) throws IOException{

InputStream socketIn=socket.getInputStream();

return new BufferedReader(new InputStreamReader(socketIn));

}

public String echo(String msg){

return "echo: "+msg;

}

@Override

public void run() {

try{

System.out.println("New connection accepted "+socket.getInetAddress()+":"+socket.getPort());

BufferedReader br=getReader(socket);

PrintWriter pw=getWriter(socket);

String msg=null;

//接收和发送数据,直到通信结束

while((msg=br.readLine())!=null){

System.out.println("from "+socket.getInetAddress()+":"+socket.getPort()+">"+msg);

pw.println(echo(msg));

if (msg.equals("bye"))

break;

}

} catch (IOException e) {

e.printStackTrace();

}finally{

try{

if (socket!=null)

socket.close();

}catch (IOException e){

e.printStackTrace();

}

}

}

}

AdminClient类(负责向EchoServer发送“shutdown”命令,关闭服务器)

package ShutdownServer;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.net.Socket;

public class AdminClient {

public static void main(String[] args){

Socket socket=null;

try{

socket=new Socket("localhost",8001);

//发送关闭命令

OutputStream socketOut=socket.getOutputStream();

//Scanner scanner=new Scanner(System.in);

//String order=scanner.next();

socketOut.write("shutdown\r\n".getBytes());

//接收服务器反馈

BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));

String msg=null;

while ((msg=br.readLine())!=null){

System.out.println(msg);

}

} catch (Exception e) {

e.printStackTrace();

}finally {

try{

if (socket!=null)

socket.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

Client类(客户,与服务器进行通讯)

package ShutdownServer;

import java.io.*;

import java.net.Socket;

public class Client {

private String host="localhost";

private int port=8000;

private Socket socket;

public Client() throws IOException {

socket=new Socket(host,port);

}

private PrintWriter getWriter(Socket socket) throws IOException{

OutputStream socketOut=socket.getOutputStream();

return new PrintWriter(socketOut,true);

}

private BufferedReader getReader(Socket socket) throws IOException{

InputStream socketIn=socket.getInputStream();

return new BufferedReader(new InputStreamReader(socketIn));

}

public void talk() throws IOException{

try{

BufferedReader br=getReader(socket);

PrintWriter pw=getWriter(socket);

BufferedReader localReader=new BufferedReader(new InputStreamReader(System.in));

String msg=null;

while((msg=localReader.readLine()) != null){

pw.println(msg);

System.out.println(br.readLine());

if (msg.equals("bye")){

break;

}

}

}catch (IOException e){

e.printStackTrace();

}

finally {

try{

socket.close();

}catch (IOException e){

e.printStackTrace();

}

}

}

public static void main(String args[]) throws IOException {

new Client().talk();

}

}

shutdownThread线程负责关闭服务器,它一直监听8001端口,如果接收到了AdminClient发送的“shutdown”命令,就把isShutdown设置为true。

在关闭服务器时,我们使用了最常用的方法,先调用线程池的shutdown()方法,接着调用线程池的awaitTermination()方法。

executorService.shutdown();

//等待关闭线程池,每次等待的超时时间为30s

//当使用awaitTermination时,主线程会处于一种等待的状态,等待线程池中所有的线程都运行完毕后才继续运行。

//如果等待的时间超过指定的时间,但是线程池中的线程运行完毕,那么awaitTermination()返回true。执行分线程已结束

//如果等待的时间超过指定的时间,但是线程池中的线程未运行完毕,那么awaitTermination()返回false。不执行分线程已结束

//如果等待时间没有超过指定时间,等待!

//可以用awaitTermination()方法来判断线程池中是否有继续运行的线程。

while(!executorService.isTerminated())

executorService.awaitTermination(30, TimeUnit.SECONDS);

在线程池执行了shutdown()方法后,线程池不会在接收新的任务,同时该线程因为调用awaitTermination()方法而发生阻塞,直到线程池中所有线程的任务执行完毕,该线程才会继续向下

运行结果

先运行EchoServer,Client,AdminClient后,再开启一客户程序Client1,显示Client1无法被加入线程池

EchoServer(只显示连接了Client,未连接Client1)

Client

Client2(向服务器发送消息,收到null)

AdminClient(在Client没有运行结束时,被阻塞)

当Client输入“bye”结束运行后,AdminClient关闭服务器

Client类

EchoServer类

AdminClient类

参考Java网络编程核心技术详解

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:网站api接口 在哪(api在哪里)
下一篇:Java实现斗地主的发牌功能
相关文章

 发表评论

暂时没有评论,来抢沙发吧~