Java网络编程精解之ServerSocket用法详解三(1)
发表于:2007-06-11来源:作者:点击数:
标签:
第3章 ServerSocket用法详解 第10章 Java 语言的反射机制 第13章 基于MVC和R MI 的分布 ServerSocket用法详解一 Java语言的反射机制一 基于MVC和RMI的分布式应用一 ServerSocket用法详解二 Java语言的反射机制二 基于MVC和RMI的分布式应用二 ServerSocket用
第3章 ServerSocket用法详解 |
第10章 Java语言的反射机制 |
第13章 基于MVC和RMI的分布 |
|
|
|
|
|
|
|
|
|
相关文章链接:
Java网络编程精解之ServerSocket用法详解一
Java网络编程精解之ServerSocket用法详解二
3.7 关闭服务器
前面介绍的EchoServer服务器都无法关闭自身,只有依靠操作系统来强行终止服务器程序。这种强行终止服务器程序的方式尽管简单方便,但是会导致服务器中正在执行的任务被突然中断。如果服务器处理的任务不是非常重要,允许随时中断,则可以依靠操作系统来强行终止服务器程序;如果服务器处理的任务非常重要,不允许被突然中断,则应该由服务器自身在恰当的时刻关闭自己。
本节介绍的EchoServer服务器就具有关闭自己的功能。它除了在8000端口监听普通客户程序EchoClient的连接外,还会在8001端口监听管理程序AdminClient的连接。当EchoServer服务器在8001端口接收到了AdminClient发送的“shutdown”命令时,EchoServer就会开始关闭服务器,它不会再接收任何新的EchoClient进程的连接请求,对于那些已经接收但是还没有处理的客户连接,则会丢弃与该客户的通信任务,而不会把通信任务加入到线程池的工作队列中。另外,EchoServer会等到线程池把当前工作队列中的所有任务执行完,才结束程序。
如例程3-10所示是EchoServer的源程序,其中关闭服务器的任务是由shutdown- Thread线程来负责的。
例程3-10 EchoServer.java(具有关闭服务器的功能)
package multithread4;
import java.io.*;
import java.net.*;
import java.util.concurrent.*; 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 serverSocketForShutdown;
private boolean isShutdown=false; //服务器是否已经关闭 private Thread shutdownThread=new Thread(){ //负责关闭服务器的线程
public void start(){
this.setDaemon(true); //设置为守护线程( 也称为后台线程)
super.start();
}
public void run(){
while (!isShutdown) {
Socket socketForShutdown=null;
try {
socketForShutdown= serverSocketForShutdown.aclearcase/" target="_blank" >ccept();
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();
//等待关闭线程池,每次等待的超时时间为30秒
while(!executorService.isTerminated())
executorService.awaitTermination(30,TimeUnit.SECONDS);
serverSocket.close(); //关闭与EchoClient客户通信的ServerSocket
long endTime=System.currentTimeMillis();
socketForShutdown.getOutputStream().write(("服务器已经关闭,"+
"关闭服务器用了"+(endTime-beginTime)+"毫秒\r\n").getBytes());
socketForShutdown.close();
serverSocketForShutdown.close();
}else{
socketForShutdown.getOutputStream().write("错误的命令\r\n".getBytes());
socketForShutdown.close();
}
}catch (Exception e) {
e.printStackTrace();
}
}
}
}; public EchoServer() throws IOException {
serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(60000); //设定等待客户连接的超过时间为60秒
serverSocketForShutdown = 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 {
socket = serverSocket.accept();
//可能会抛出SocketTimeoutException和SocketException
socket.setSoTimeout(60000); //把等待客户发送数据的超时时间设为60秒
executorService.execute(new Handler(socket));
//可能会抛出RejectedExecutionException
}catch(SocketTimeoutException e){
//不必处理等待客户连接时出现的超时异常
}catch(RejectedExecutionException e){
try{
if(socket!=null)socket.close();
}catch(IOException x){}
return;
}catch(SocketException e) {
//如果是由于在执行serverSocket.accept()方法时,
//ServerSocket被ShutdownThread线程关闭而导致的异常,就退出service()方法
if(e.getMessage().indexOf("socket closed")!=-1)return;
}catch(IOException e) {
e.printStackTrace();
}
}
} public static void main(String args[])throws IOException {
new EchoServer().service();
}
}
/** 负责与单个客户通信的任务,代码与3.6.1节的例程3-5的Handler类相同 */
class Handler implements Runnable{…}
|