1. 使用QSAdminServer
当我们需要一个管理服务器来控制我们的服务器时,我们不需要修改代码甚至关闭正在运行的服务器。这项服务的实现类是:
org.quickserver.net.qsadmin.QSAdminServer
要使用它的功能我们要调用QuickServer的startQSAdminServer()方法。QSAdminServer运行的默认端口是9876,我们可以使用下面两个方法之一修改它:
setQSAdminServerPort(4124);
getQSAdminServer().getServer().setPort(4124);
下面是能够在EchoServer 的4124端口运行QSAdminServer 的代码:
01 package echoserver; 02 03 import org.quickserver.net.*; 04 import org.quickserver.net.server.*; 05 06 import java.io.*; 07 08 public class EchoServer { 09 public static void main(String s[]) { 10 11 String cmd = "echoserver.EchoCommandHandler"; 12 String auth = "echoserver.EchoServerQuickAuthenticator"; 13 String data = "echoserver.EchoServerPoolableData"; //Poolable 14 15 QuickServer myServer = new QuickServer(cmd); 16 myServer.setAuthenticator(auth); 17 myServer.setClientData(data); 18 19 myServer setPort(4123); 20 myServer.setName("Echo Server v 1.0"); 21 22 //config QSAdminServer 23 myServer.setQSAdminServerPort(4124); 24 myServer.getQSAdminServer().getServer().setName("EchoAdmin v 1.0"); 25 try { 26 myServer.startQSAdminServer(); 27 myServer.startServer(); 28 } catch(AppException e){ 29 System.out.println("Error in server : "+e); 30 } 31 } 32 } 33 |
这样,我们定义了我们的QSAdminServer运行在4124端口。但是它怎样进行验证呢?如果没有一个外在的验证器,QSAdminServer将使用org.quickserver.net.qsadmin.Authenticator做为它的验证器。查阅API文档我们可以发现它非常简单,用户名和密码都被硬编码为:
用户名 : Admin
密码 : QsAdm1n
现在让我们编译新的程序并运行之,控制台将会输出信息以说明服务器运行于4124端口。
在QuickServer安装目录下的bin目录下运行QsAdminGUI.bat,QsAdmin的界面如下所示
现在可以连接到管理服务器了。点击右上角的"Login"按钮,将会弹出一个登录对话框如下图,输入IP地址和服务器运行端口:127.0.0.1、4124,因为我们使用默认的用户名密码,直接点击"Login"登录。
登录后界面将会显示欢迎及登录成功信息。现在可以选择发送命令的目标服务器(Target)及左边一排命令按钮所示的操作。
Target是基于发送命令的服务器,因为我们目前有两个服务器EchoServer和EchoAdmin。
界面右下边有一个可以直接向服务器发送消息的文本框,命令可以参考QsAdmin command handler:
org.quickserver.net.qsadmin.CommandHandler API文档
若想要改变服务器的配置,可以点选"Get/Set"书签,只要选择"Target",点击"Reload Properties For The Target"以重新加载目标服务器的配置。修改好参数,然后点击"Save"就可以了。部分参数的生效需要重启服务器,不过这样不会断开与客户端的连接。
2. 添加自己的命令
前面讲过如果我们想改变一些服务器的属性,我们无须修改已有的代码或重启服务器,我们可以添加自己的命令来管理服务器。
让我们用一个例子来演示这个功能。当用户发送"What's interest"(利息是多少)时,我们将要显示当前的利率。这个数字存贮在一个对象中,如果需要的话,无须重启服务器就可以改变它。我们说它是可变的并且当服务器运行时我们需要改变它。
我们来实现command handler以显示利率。首先要改变EchoServer和command handler。下面是代码:
01 package echoserver; 02 03 import org.quickserver.net.*; 04 import org.quickserver.net.server.*; 05 06 import java.io.*; 07 08 public class EchoServer { 09 public static void main(String s[]) { 10 11 String cmd = "echoserver.EchoCommandHandler"; 12 String auth = "echoserver.EchoServerQuickAuthenticator"; 13 String data = "echoserver.EchoServerPoolableData"; //Poolable 14 15 QuickServer myServer = new QuickServer(cmd); 16 myServer.setAuthenticator(auth); 17 myServer.setClientData(data); 18 19 myServer.setPort(4123); 20 myServer.setName("Echo Server v 1.0"); 21 22 //store data needed to be changed by QSAdminServer 23 Object[] store = new Object[]{"12.00"}; 24 myServer setStoreObjects(store); 25 26 //config QSAdminServer 27 myServer.setQSAdminServerPort(4124); 28 myServer.getQSAdminServer().getServer().setName("EchoAdmin v 1.0"); 29 try { 30 myServer.startQSAdminServer(); 31 myServer.startServer(); 32 } catch(AppException e){ 33 System.out.println("Error in server : "+e); 34 } 35 } 36 } 37 |
01 // EchoCommandHandler.java 02 package echoserver; 03 04 import java.net.*; 05 import java.io.*; 06 import org.quickserver.net.server.ClientCommandHandler; 07 import org.quickserver.net.server.ClientHandler; 08 09 public class EchoCommandHandler implements ClientCommandHandler { 10 11 public void gotConnected(ClientHandler handler) 12 throws SocketTimeoutException, IOException { 13 handler.sendClientMsg("+++++++++++++++++++++++++++++++"); 14 handler.sendClientMsg("| Welcome to EchoServer v 1.0 |"); 15 handler.sendClientMsg("| Note: Password = Username |"); 16 handler.sendClientMsg("| Send 'Quit' to exit |"); 17 handler.sendClientMsg("+++++++++++++++++++++++++++++++"); 18 } 19 public void lostConnection(ClientHandler handler) 20 throws IOException { 21 handler.sendSystemMsg("Connection lost : " + 22 handler.getSocket().getInetAddress()); 23 } 24 public void closingConnection(ClientHandler handler) 25 throws IOException { 26 handler.sendSystemMsg("Closing connection : " + 27 handler.getSocket().getInetAddress()); 28 } 29 30 public void handleCommand(ClientHandler handler, String command) 31 throws SocketTimeoutException, IOException { 32 if(command.equals("Quit")) { 33 handler.sendClientMsg("Bye ;-)"); 34 handler.closeConnection(); 35 return; 36 } 37 if(command.equals("What's interest?")) { 38 handler.sendClientMsg("Interest is : "+ 39 (String)handler.getServer().getStoreObjects()[0]+ 40 "%"); 41 } else if(command.equalsIgnoreCase("hello")) { 42 EchoServerData data = (EchoServerData) handler.getClientData(); 43 data.setHelloCount(data.getHelloCount()+1); 44 if(data.getHelloCount()==1) { 45 handler.sendClientMsg("Hello "+data.getUsername()); 46 } else { 47 handler.sendClientMsg("You told Hello "+data.getHelloCount()+ 48 " times. "); 49 } 50 } else { 51 handler.sendClientMsg("Echo : "+command); 52 } 53 } 54 } |
接下来为QSAdminServer 添加Command插件
01 package echoserver; 02 03 04 import java.io.*; 05 import java.net.SocketTimeoutException; 06 import org.quickserver.net.server.*; 07 import org.quickserver.net.qsadmin.*; 08 09 public class QSAdminCommandPlugin implements CommandPlugin { 10 /** 11 * Echoserver commands 12 * ---------------------------------- 13 * set interest value 14 * get interest 15 */ 16 public boolean handleCommand(ClientHandler handler, String command) 17 throws SocketTimeoutException, IOException { 18 19 QuickServer echoserver = (QuickServer) 20 handler.getServer().getStoreObjects()[0]; 21 Object obj[] = echoserver.getStoreObjects(); 22 23 if(command.toLowerCase().startsWith("set interest ")) { 24 String temp = ""; 25 temp = command.substring("set interest ".length()); 26 obj[0] = temp; 27 echoserver.setStoreObjects(obj); 28 handler.sendClientMsg("+OK interest changed"); 29 return true; 30 } else if(command.toLowerCase().equals("get interest")) { 31 handler.sendClientMsg("+OK " + (String)obj[0]); 32 return true; 33 } 34 //ask QSAdminServer to process the command 35 return false; 36 } 37 } |
QuickServer echoserver = (QuickServer)handler.getServer().getStoreObjects()[0];
如果进程获得了一个命令,返回true,否则返回false,并指明QSAdminServer的默认命令处理器将被用来处理命令。同样的技术将被使用于覆写QSAdminServer命令处理器的默认命令。
让我们告诉QuickServer这个类是QSAdminServer的Command插件。修改后的EchoServer.java代码如下:
01 package echoserver; 02 03 import org.quickserver.net.*; 04 import org.quickserver.net.server.*; 05 06 import java.io.*; 07 08 public class EchoServer { 09 public static void main(String s[]) { 10 11 String cmd = "echoserver.EchoCommandHandler"; 12 String auth = "echoserver.EchoServerQuickAuthenticator"; 13 String data = "echoserver.EchoServerPoolableData"; //Poolable 14 15 QuickServer myServer = new QuickServer(cmd); 16 myServer.setAuthenticator(auth); 17 myServer.setClientData(data); 18 19 myServer.setPort(4123); 20 myServer.setName("Echo Server v 1.0"); 21 22 //store data needed to be changed by QSAdminServer 23 Object[] store = new Object[]{"12.00"}; 24 myServer.setStoreObjects(store); 25 26 //config QSAdminServer 27 myServer.setQSAdminServerPort(4124); 28 myServer.getQSAdminServer().getServer().setName("EchoAdmin v 1.0");29 try { 30 //add command plugin 31 myServer.getQSAdminServer().setCommandPlugin( 32 "echoserver.QSAdminCommandPlugin"); 33 myServer startQSAdminServer(); 34 myServer.startServer(); 35 } catch(AppException e){ 36 System.out.println("Error in server : "+e); 37 } catch(Exception e){ 38 System.out.println("Error : "+e); 39 } 40 } 41 } |
编译代码,并运行。现在打开客户端如SocketTest,发送命令"What's interest?",将显示"Interest is : 12.00%"。
运行QSAdminGUI,在发送消息框中键入以下命令,发送:
get interest
系统输出"+OK 12.00"
现在把这个参数修改一下,发送下面的命令
set interest 15.00
系统输出"+OK interest changed"
再次在客户端发送命令"What's interest?",客户端显示"Interest is : 15.00%"。