教你利用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; import java.util.concurrent.TimeUnit; public class EchoServer { private int port=8000; private ServerSocket serverSocket; private ExecutorService executorService; //线程池 private final int POOL_SIZE=4; //单个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网络编程核心技术详解
到此这篇关于教你利用JAVA实现可以自行关闭服务器的方法的文章就介绍到这了,更多相关JAVA自行关闭服务器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
JAVA面试题 简谈你对synchronized关键字的理解
这篇文章主要介绍了JAVA面试题 请谈谈你对Sychronized关键字的理解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下2019-07-07关于@PostConstruct、afterPropertiesSet和init-method的执行顺序
这篇文章主要介绍了关于@PostConstruct、afterPropertiesSet和init-method的执行顺序,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2021-09-09Spring Cloud OAuth2实现自定义token返回格式
Spring Security OAuth的token返回格式都是默认的,但是往往这个格式是不适配系统。本文将用一个接口优雅的实现 Spring Cloud OAuth2 自定义token返回格式,需要的可以参考一下2022-06-06Mybatis和orcale update语句中接收参数为对象的实例代码
Mybatis的 mapper.xml 中 update 语句使用 if 标签判断对像属性是否为空值。本文重点给大家介绍Mybatis和orcale update语句中接收参数为对象的实例代码,需要的朋友参考下吧2017-09-09
最新评论