国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Java后臺服務程序設計

2019-11-18 14:09:22
字體:
來源:轉載
供稿:網友

  內容:

為什么需要后臺服務程序?
通用服務器框架
服務與監聽
服務控制
服務器實現和運行
參考資源
作者簡介

何千軍 (heqianjun@163.net)
軟件工程師,獨立顧問和自由撰稿人

在很多大型軟件項目中,都有一些極為重要的后臺服務程序,它們并不處理具體的系統業務邏輯,但對整個系統資源和服務的協調治理卻是不可或缺。本文討論如何完整地編寫一個后臺服務治理程序,并通過一個具體的后臺服務治理例子來說明這一技術實現的技巧。
為什么需要后臺服務程序?
在許多大型軟件項目中,后臺服務程序都扮演著極為重要的角色。它們無處不在,例如操作系統的內核程序處理各種對操作系統的內部調用;數據庫系統的核心治理進程處理各種對數據庫的讀寫操作和進程、資源的治理;大型ERP軟件的內核治理程序要完成各種應用模塊的資源、通訊治理等等。它們使系統的各種服務、資源與應用的表示之間形成了一個松耦合關系,這樣就極大地增加了軟件系統的穩定性和伸縮性。后臺服務程序也就是相當于軟件系統的治理調度中心,它是軟件系統的中心處理器,是保證應用高效運行的內核程序。

在不同的軟件系統中,由于軟件的復雜程度和功能的不同使得各種軟件系統的后臺服務程序都有存在較大的差異。但是后臺服務程序還是有很多共同的特點,一個基本的后臺服務程序大概可以由四個部分構成:通用服務器框架、服務與監聽、服務控制、服務器實現。下面我們就使用具體的代碼來實現一個基本的后臺服務器程序。

通用服務器框架
在開發后臺服務程序中,我們首先實現一個通用服務器框架類,它能在多個端口提供多線程的服務(由多個Service對象定義),并且能夠在系統運行時動態地調用和實例化Service類并加載新的服務或卸除已加載的服務。

清單 1顯示了如何編制一個通用服務器框架類文件。

【清單 1:通用服務器框架類文件Server.java

import java.util.*;
import java.io.*;
import java.net.*;

public class Server {

PRotected Map services;
Set connections;
int maxConnections;
int freeConn;

ThreadGroup threadGroup;
private int currentConn;
private PrintWriter log = new PrintWriter(System.out, true);
public boolean connected = false;
public Properties proPort, proNum;

public synchronized void setControlFlag() {
connected = true;
}

public synchronized void removeControlFlag() {
connected = false;
}

public void setProperty(Properties proPort, Properties proNum) {
this.proPort = proPort;
this.proNum = proNum;
}

public Server(int maxConn) {
this.maxConnections = maxConn;
this.freeConn=maxConnections;
this.threadGroup = new ThreadGroup(Server.class.getName());
currentConn = 0;
this.services = new HashMap();
this.connections = new HashSet(maxConnections);
}

public synchronized void addService(Service service,int port, int maxConn) throws IOException {
String servicename = service.getClass().getName();
Integer key = new Integer(port);
if (services.get(key) != null) throw new IllegalArgumentException("端口:" + port + " 已經被占用!");
if (getfreeConnections(maxConn)>=0) {
Listener listener = new Listener(this, port, service, maxConn);
services.put(key,listener);
log.println("啟動" + servicename + "服務在" + port +"端口上");
listener.start();
} else {
System.err.println("系統并發連接限制已經達到最大值!");
System.err.println("服務" + servicename + " 啟動失敗!");
}
}


public synchronized void addService(Service service,int port) throws IOException {
this.addService(service,port,10);
}

public synchronized boolean removeService(int port) {
Integer key = new Integer(port);
int maxConn =10;
final Listener listener = (Listener) services.get(key);
if (listener == null) {
log.println("Service " + " isn′t started on port " + port);
return false;
}

services.remove(key);
listener.pleaseStop();
freeConn+=listener.maxConn;
log.println("Close " + listener.service + " on port " + port);
return true;
}

public synchronized void displayStatus(PrintWriter out) {
Iterator keys = services.keySet().iterator();
while (keys.hasNext()) {
Integer port = (Integer) keys.next();
Listener listener = (Listener) services.get(port);
out.println("服務" + listener.service + "運行" + port + " ");
}

out.println("連接限制為" + maxConnections);

Iterator conns = connections.iterator();
while (conns.hasNext()) {
Socket s = (Socket) conns.next();
int sport = s.getLocalPort();
Listener listen = (Listener) services.get(new Integer(sport));
String servicename = listen.service;
out.println(servicename + "響應請求在" + s.getInetAddress().getHostAddress() + "的" + sport + "端口上");
}

out.println("當前連接數為" + currentConn);
out.println("當前系統空閑連接數為" + freeConn);
}

private synchronized int getfreeConnections(int maxConn) {
int num = -1;
if (freeConn >= maxConn) {
freeConn-=maxConn;
num = freeConn;
}
return num;
}

public synchronized int getConnections() {
return currentConn;
}

public synchronized int addConnections(Socket s) {
connections.add(s);
return currentConn++;
}

public synchronized int removeConnections(Socket s) {
connections.remove(s);
try {
s.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
return currentConn--;
}

public synchronized int getConnections(int connections) {
int num = 0;
if ((num=freeConn-connections) >= 0) {
freeConn = num;
} else num = -1;
return num;
}

private synchronized int getFreeConn() {
return freeConn;
}
}






如上所述可知,服務器框架類Server主要是通過端口到監聽器影射的散列表services來治理服務對象,Server類的幾個主要方法說明如下:

addService方法:此方法能夠在特定的端口上創建新的服務,即在指定端口上運行指定的Service對象。

removeService方法:此方法使服務器停止指定端口上的服務,并不終止連接,僅使服務器停止接受新的連接。

displayStatus方法:此方法用于打印指定流上服務器的狀態信息。

服務與監聽
每個服務都對應著一個監聽對象,監聽指定端口的連接并在獲得連接請求時調用addConnection(Socket s, Service service)方法來取得(釋放)一個連接。清單 2顯示了如何編制一個監聽類文件。
【清單 2:Listener.java的一個簡單實現】

import java.util.*;
import java.io.*;
import java.net.*;

public class Listener extends Thread {
private ServerSocket listener;
private int port;
String service;
Set connections;
private Service runService;
private boolean stop_flag = false;
int maxConn;
private PrintWriter log = new PrintWriter(System.err, true);
private ThreadGroup group;
private int currentConnections = 0;
Server server;
Socket client = null;

public Listener(Server server, int port, Service service, int maxConn, boolean bl) throws IOException {

this.server = server;
this.port = port;
this.service = service.getClass().getName();
this.maxConn = maxConn;
this.group = server.threadGroup;
this.connections = server.connections;
listener = new ServerSocket(this.port);
if (bl == false) listener.setSoTimeout(600000);
this.runService = service;
if (!stop_flag) {
for (int i=0;i<this.maxConn;i++) {
ConnectionHandler currentThread = new ConnectionHandler(server,logStream);
new Thread(this.group, currentThread, this.service+this.port+i).start();
this.logStream.realLog("向線程組" + group.toString() + "添加一個線程" + this.service+this.port+i);
}
} else throw new IllegalArgumentException("系統并發連接限制已經超過最大值!!");
}

public Listener(Server server, int port, Service service, int maxConn) throws IOException {
this(server, port, service, maxConn, false);
}


public void pleaseStop() {
this.stop_flag = true;

try {
listener.close();
} catch (Exception e) {
}
this.interrupt();
}

public void run() {

while(!stop_flag) {
try {
client = listener.accept();
addConnection(client,runService);
} catch (Exception e) {}
}

try {
client.close();
} catch (IOException e) {}
}

private synchronized void addConnection(Socket s, Service service) {
ConnectionHandler.requestToHandler(s, service);
}

}


在實際處理過程中,Listener對象通過在指定端口上與指定服務的綁定實現監聽過程,主要的幾個方法說明如下:
pleaseStop:以禮貌的方法停止接受連接。
addConnection:把指定要處理的服務放到線程池中,以等待空閑的線程處理服務。
監聽對象通過傳遞一個Service對象并喚醒它的serve()方法才真正提供了服務。下面我們就來實現一個具體的服務:

服務接口Service只有一個抽象方法serve(InputStream in, OutputStream out),它所有服務實現所必須重寫的一個方法,Listing 3顯示了一個Service接口的定義。 【清單 3:定義一個Service接口】

import java.io.*;
import java.net.*;

public interface Service {
public void serve(InputStream in, OutputStream out) throws IOException;
}




編寫一個簡單的顯示時間服務類:見清單 4。 【清單 4:一個顯示系統當前時間的服務類Timer.java】

import java.util.*;
import java.text.*;
import java.io.*;
import java.net.*;

public class Timer implements Service {

public Timer() {

}

public void serve(InputStream in, OutputStream out) throws IOException {
String timeFormat = "yyyy-MM-dd hh:mm:ss";
SimpleDateFormat timeFormatter = new SimpleDateFormat(timeFormat);
BufferedReader from_client = new BufferedReader(new InputStreamReader(in));
PrintWriter outPrint = new PrintWriter(out);
String sDate = timeFormatter.format(new Date());

outPrint.println("當前時間是:" + sDate);
outPrint.flush();
try {
from_client.close();
outPrint.close();
}catch (Exception e){}
}
}



通過實現Service接口可以編寫很多的服務實現提供各種不同的服務,讀者有愛好也可自己編寫一個服務來測試一下。

服務控制
服務控制是在服務器運行時動態地操作控制服務器,如系統運行時,動態地裝載(卸載)服務,顯示服務器的狀態信息等等。為了簡化基本后臺服務系統的復雜程度,我們采用創建一個ControlService服務實例來在運行時治理服務器。ControlService實現了基于命令的協議,可用密碼保護操縱服務器,代碼如清單 5所示:

【清單 5:服務控制類文件ControlService.java】
import java.io.*;
import java.util.*;
import java.net.*;

import dvb.kuanshi.kssms.util.*;
import dvb.kuanshi.kssms.server.Server;

public class ControlService implements Service {
Server server;
String passWord;

public ControlService(Server server, String password) {
this.server = server;
this.password = password;
}

public void serve(InputStream in, OutputStream out) throws IOException {

boolean authorized = false;
BufferedReader from_client = new BufferedReader(new InputStreamReader(in));
PrintWriter to_console = new PrintWriter(System.out, true);
to_console.println("后臺治理服務響應請求! ");
PrintWriter to_client = new PrintWriter(out);
synchronized (this) {
if(server.connected) {
to_client.println("已經有用戶連接,本服務僅答應一個連接! ");
to_client.close();
return;
} else server.setControlFlag();
}

to_client.println("Remote Console>");
to_client.flush();

String line;

while ((line=from_client.readLine())!=null) {

int len = line.indexOf("Remote Console>");
line = line.substring(len+1,line.length());
String printStr;
try {
StringTokenizer st = new StringTokenizer(line);
int count = st.countTokens();
if (!st.hasMoreElements()) continue;

String first = st.nextToken().toLowerCase();
if (first.equals("password")) {
String pwd = st.nextToken();
if (pwd.equals(this.password)) {
to_client.println("OK");
authorized = true;
} else to_client.println("密碼無效,請重試! ");

} else if (first.equals("add")) {
if(!authorized) to_client.println("請登陸! ");
else {
count--;
String servicename;
int Port;
boolean flag = true;
if (count>0) {
servicename = st.nextToken();
Port = Integer.parseInt(st.nextToken());
server.addService(loadClass(servicename1), Port);
to_client.println("服務" + servicename + "已經加載 ");
flag = false;
}
if (flag) to_client.println("系統不能啟動非法服務:" + servicename);
else {to_client.println("請輸入服務名! ");}
}
} else if (first.equals("remove")) {
if(!authorized) to_client.println("請登陸! ");
else {
count--;
if (count>0) {
int port = Integer.parseInt(st.nextToken());
boolean bl = server.removeService(port);
if (bl) to_client.println("端口: " + port +"上的服務已經卸載 ");
else to_client.println("端口: "+ port +"上無任何服務運行,卸載操作失敗! ");
} else to_client.println("請輸入端口名! ");
}
} else if(first.equals("status")) {
if(!authorized) to_client.println("請登陸! ");
else server.displayStatus(to_client);
} else if(first.equals("help")) {
if(!authorized) to_client.println("請登陸! ");
else printHelp(to_client);
} else if(first.equals("quit")) break;
else to_client.println("命令不能識別! ");
} catch(Exception e) {to_client.println("系統后臺出錯" + e.getMessage() +" ");
printHelp(to_client);
}
to_client.println("Remote Console>");
to_client.flush();
}
to_client.flush();
authorized = false;
server.removeControlFlag();
to_client.close();
from_client.close();
}

private void printHelp(PrintWriter out) {
out.println("COMMANDS:" +
" password <password> " +
" add <servicename> <port> " +
" remove <port> " +
" status " +
" help " +
" quit ");
}

protected Service loadClass(String servicename) {
Service s = null;

try {
Class serviceClass = Class.forName(servicename);
s = (Service) serviceClass.newInstance();
} catch (Exception e) {
}

return s;
}
}



服務器實現和運行
服務器實現主要完成服務器的初始化,啟動服務控制實例等工作,代碼如清單 6所示:


【清單 6:runServer.java的一個簡單實現】
import java.util.*;

public class runServer {
public runServer() {
}

public static void main(String[] args) {
try {
int argLen = args.length;
System.out.println("正在初始化系統請等待......");
System.out.println("");
int maxConn = 30;

Server server = new Server(maxConn);

System.out.println("################################################################");
System.out.println("# #");
System.out.println("# 后臺服務治理系統 #");
System.out.println("# #");
System.out.println("################################################################");
System.out.println();
if (argLen>2) {
for (int i = 0;i<argLen;i++) {
if (args[i].equals("-s")) {
i++;
String password = args[i];
i++;
int port = Integer.parseInt(args[i]);
server.addService(new ControlService(server,password), port, 2);
} else {
String servicename = args[i];
i++;
int port = Integer.parseInt(args[i]);
server.addService(loadClass(servicename), port);
}
}

} else throw new IllegalArgumentException("參數數目不正確!");
System.out.println("系統啟動,進入監聽服務模式......");
} catch (Exception e) {
throw new IllegalArgumentException(e.getMessage());
}
}

protected static Service loadClass(String servicename) {
Service s = null;
try {
Class serviceClass = Class.forName(servicename);
s = (Service) serviceClass.newInstance();
} catch (Exception e) {
}
return s;
}
}


 
下面我們就可以啟動示例程序來測試一下了。

如清單 7所示,以密碼保護方式(密碼為test)啟動后臺服務,在6809啟動服務控制實例,在6810端口啟動。

【清單 7:啟動后臺服務程序】
% java runServer -s test 6809 Timer 6810





在另外一個窗口,執行如下命令,將顯示當前系統的時間。

% java clientConnect 6810



在另外一個窗口,執行如下命令,你將能查看系統服務狀態信息,并動態地裝載你寫的服務對象,你可以測試一下。

% java clientConnect 6809



現在,一個基本的后臺服務程序即編制完成了。實際上,一個大型軟件的后臺服務程序是非常復雜的,上面的例子希望能起到拋磚引玉的效果。要寫出性能良好的后臺服務程序還有很多工作要做。

參考資源

要了解更多的 Java信息,請閱讀 java.sun.com的 主頁。
下載后臺服務程序示例全部代碼:code.zip

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 巴塘县| 东宁县| 章丘市| 南通市| 镇远县| 同仁县| 玉龙| 双流县| 铜鼓县| 吴堡县| 宜春市| 凉山| 怀来县| 全椒县| 栖霞市| 桂阳县| 布拖县| 佛山市| 将乐县| 洞头县| 霍林郭勒市| 南靖县| 泽库县| 邯郸县| 裕民县| 古蔺县| 阿瓦提县| 兴和县| 光山县| 壶关县| 长治县| 观塘区| 富川| 沁水县| 类乌齐县| 高清| 乌海市| 增城市| 武山县| 高平市| 阿荣旗|