教你利用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自行关闭服务器内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 教你用Java验证服务器登录系统

    一.前言 代码全部由自己所写,作者是一名小白请多多包涵,如果代码有什么不好的地方大佬们可以指出问题 单独写一个这样简易的登录是因为比较方便,由于我尝试了多次在写好的程序内直接写这个登录系统测试,很麻烦.不方便,所以单独写出了这套代码,个人觉得这样把写好的程序放进去修改就比较方便多了 二.登录系统服务端 import java.io.*; import java.net.ServerSocket; import java.net.Socket; public class ServerLogin {

  • Java 如何实现一个http服务器

    在Java中可以使用HttpServer类来实现Http服务器,该类位于com.sun.net包下(rt.jar).实现代码如下: 主程序类 package bg.httpserver; import com.sun.net.httpserver.HttpServer; import java.io.IOException; import java.net.InetSocketAddress; import java.util.concurrent.Executors; public class

  • Java 实现简单静态资源Web服务器的示例

    需求 有时候我们想快速通过http访问本地的一些资源,但是安装一些web服务器又很费时和浪费资源,而且也不是长期使用的. 这时候我们可以启动一个小型的java服务器,快速实现一个http的静态资源web服务器. 难点 其实没什么难点,主要是注意请求头和返回头的处理.然后将请求的文件以流的方式读入返回outputstream即可. 代码 直接上代码吧- import java.io.IOException; import java.io.InputStream; import java.io.Ou

  • Java上传文件FTP服务器代码实例

    FTP服务器(File Transfer Protocol Server)是在互联网上提供文件存储和访问服务的计算机,它们依照FTP协议提供服务. FTP是File Transfer Protocol(文件传输协议).顾名思义,就是专门用来传输文件的协议.简单地说,支持FTP协议的服务器就是FTP服务器. 在实际的应用中,通常是通过程序来进行文件的上传. 1.实现java上传文件到ftp服务器中 2.新建maven项目 添加依赖 <dependency> <groupId>comm

  • Java Red5服务器实现流媒体视频播放

    引言 流媒体文件是目前非常流行的网络媒体格式之一,这种文件允许用户一边下载一边播放,从而大大减少了用户等待播放的时间.另外通过网络播放流媒体文件时,文件本身不会在本地磁盘中存储,这样就节省了大量的磁盘空间开销.正是这些优点,使得流媒体文件被广泛应用于网络播放. 流媒体服务器是通过建立发布点来发布流媒体内容和管理用户连接的.流媒体服务器能够发布从视频采集卡或摄像机等设备中传来的实况流,也可以发布事先存储的流媒体文件,并且发布实况流和流媒体文件的结合体.一个媒体流可以由一个媒体文件构成,也可以由多个

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

    JAVA实现可以自行关闭的服务器 普通实现的服务器都无法关闭自身,只有依靠操作系统来强行终止服务程序.这种强行终止服务程序的方式尽管简单方便,但会导致服务器中正在执行的任务突然中断.如果服务器处理的任务非常重要,不允许被突然中断,应该由服务器自身在恰当的时刻关闭自己 代码如下: EchoServer类 package ShutdownServer; import java.io.*; import java.net.ServerSocket; import java.net.Socket; im

  • 利用java反射机制调用类的私有方法(推荐)

    试想一下,如果你可以轻易地调用一个类的私有方法,那么是不是说你的封装都失效了?最近在看java的反射机制,发现居然可以利用java的反射机制去调用其他类的私有方法,至于这能干什么,那就见人见智了.. 我写的一段简易实例代码如下: import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * @author thomaslwq * @version 创建时间:Sep 4, 201

  • 利用Java如何获取IP与机器名方法示例

    前言 本文详细给大家介绍了关于利用Java如何获取IP与机器名的方法示例,分享出来供大家参考学习,下面话不多说,来一起看看详细的介绍: 一.通过IP获取机器名 or 通过机器名获取ip host :主机        hostAddress :ip       hostName:机器名 import java.net.InetAddress; import java.net.UnknownHostException; public class Test01 { public static voi

  • java利用java.net.URLConnection发送HTTP请求的方法详解

    一.前言 如何通过Java发送HTTP请求,通俗点讲,如何通过Java(模拟浏览器)发送HTTP请求. Java有原生的API可用于发送HTTP请求,即java.net.URL.java.net.URLConnection,这些API很好用.很常用,但不够简便: 所以,也流行有许多Java HTTP请求的framework,如,Apache的HttpClient. 目前项目主要用到Java原生的方式,所以,这里主要介绍此方式. 二.运用原生Java Api发送简单的Get请求.Post请求步骤

  • 利用java批量给pdf加水印的方法示例

    前言 最近因为工作需要,要批量在pdf上加水印,但找了一圈pdf在mac下的水印工具,都不太好用,索性就用java写一个吧. 以下代码依赖itext5.3.3包,java操作pdf 依靠itext5.3.3. 示例代码 //读取原来的pdf PdfReader reader = new PdfReader("/test/" + "1.pdf"); //生成以后的pdf PdfStamper stamp = new PdfStamper(reader, new Fil

  • 利用node.js搭建简单web服务器的方法教程

    前言 使用Nodejs搭建Web服务器是学习Node.js比较全面的入门教程,因为要完成一个简单的Web服务器,你需要学习Nodejs中几个比较重要的模块,比如:http协议模块.文件系统.url解析模块.路径解析模块.以及301重定向问题,下面我们就简单讲一下如何来搭建一个简单的Web服务器. 早先不使用web服务器的情况下想要在浏览器端访问本地资源,可以利用firefox浏览器,其可以自己启动一个小型web服务器. 为了让刚接触node的人也能大体看懂,本文的代码我将尽量简化. 准备 首先,

  • weblogic 8.1下重新编译java类但不用重启服务器的方法

    重新编译jsp是不用重启服务期的,但类就需要. 所以需要设置一下:: 在weblogic.xml文件里加上下面的一句即可(红色标示) <weblogic-web-app>   <container-descriptor>     <servlet-reload-check-secs>-1</servlet-reload-check-secs>   </container-descriptor> <context-root>ccbroo

  • 手把手教你用Java实现一套简单的鉴权服务

    前言 时遇JavaEE作业,题目要求写个简单web登录程序,按照老师的意思是用servlet.jsp和jdbc完成.本着要么不做,要做就要做好的原则,我开始着手完成此次作业(其实也是写实训作业的用户鉴权部分),而之前写项目的时候也有相关经验,这次正好能派上用场. 一.何为鉴权服务 引用百度百科的话说 鉴权(authentication)是指验证用户是否拥有访问系统的权利. 鉴权包括两个方面: 用户鉴权,网络对用户进行鉴权,防止非法用户占用网络资源. 网络鉴权,用户对网络进行鉴权,防止用户接入了非

  • 教你用Java在个人电脑上实现微信扫码支付

    Java实现PC微信扫码支付 做一个电商网站支付功能必不可少,那我们今天就来盘一盘微信支付. 微信支付官方网站 业务流程: 开发指引文档 支付服务开发前提准备: 1.SDK下载:SDK 2.利用外网穿透,获得一个外网域名:natapp 3.APPID,商户ID,密钥 注:上面三个参数需要自己申请 开发阶段: 导入依赖: <!--eureka的客户端依赖--> <dependency> <groupId>org.springframework.cloud</grou

  • 如何利用Java AWT 创建一个简易计算器

    目录 一.关于AWT 二.逻辑部分 1.对于数字按钮 2.对于算术按钮 3.对于等号按钮 4.对于清除按钮 5.对于退格按钮 6.特殊插件功能 7.==例如==: 三.GIF演示 四.附完整代码 摘要:手把手教你使用 Java AWT 创建一个简易计算器. 一.关于AWT AWT (抽象窗口工具包)是一个有助于构建 GUI 的 API (图形用户界面)基于 java 应用程序.GUI使用一些图形帮助用户交互.它主要由一组的类和方法所必需的,如在一个简化的方式创建和管理的GUI按钮,窗口,框架,文

随机推荐