c语言sscanf函数的用法是什么
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小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~