許多程序只允許啟動單個實例,比如我們常用的MSN、OUTLOOK等等。單實例有很多好處,其中最重要一點即是安全。想像一下多人同時修改同一文件的危險,就如我們在J2EE應用程序中所做的那樣,要盡可能考慮到多用戶同時訪問的問題。
前些日子用SWING為朋友寫了一個程序,其中就有不可同時啟動多個系統實例的要求。由于沒有一個好的思路,所以走了很多彎路?,F在終于解決了,積累了一些心德想與大家分享。
初遇該問題時,我首先想到的是進程。當程序啟動時判斷操作系統中是否存在該進程,如果存在就退出啟動,否則啟動程序。這個方法在VB或C語言中可以通過調用WIN32?API來實現。在JAVA中,要想實現該方法或許還要借助C的力量。(對于JAVA如何捕獲進程,還請批評指正。)
放棄了第一種方法,想到了弱智的方法--配置文件。當系統第一次啟動時將標識設置為啟動中,退出時將標識設置為未啟動。但很快就發現,當非法關閉程序(比如關機時未及時關閉程序)后,我們的程序便永遠長眠了。
其實,在該程序中,最限制我們思路的便是"單機版"這三個字。它給我們的印象是僅供一臺機器單獨使用,與網絡無關的。因此,我們很難將思路整理到服務器與客戶機中去。但要解決該問題恰恰要用到服務器與客戶機的概念。想像一下我們平時啟動電腦的步驟,首先按下加電,有了電,電腦才能啟動。沒錯,只有當電腦未加電,也就是說當我們首次啟動電腦時才會做這個動作,而且這個動作在一段時間內只會做一次。若要重新加電,就必需先斷電?,F在回到我們的程序,有了這個思路,留給我們的問題就是誰來充當電的角色呢?沒錯,就是之前提到過的服務器。程序首次啟動時首先連接指定端口的服務器,發現服務器并未啟動,于是啟動服務器,啟動程序。當程序復數啟動時,再次連接服務器,這時發現服務器已經啟動了,于是就終止啟動。代碼如下:?
public?class?Console?{
??/**端口號*/
??private?static?int?iPort?=?50000;
??/**主窗口*/
??JFrame?frame?=?null;?
??/**
??*?系統入口
??*?@param?String[]?args
??*?*/
??public?static?void?main(String[]?args)?throws?Exception?{
????Socket?socket?=?null;?//客戶端連接器
????Thread?thread?=?null;?//啟動服務器的線程
????try?{
??????//連接服務器
??????//如果服務器未啟動則拋異常
??????(socket?=?new?Socket("localhost",?iPort)).close();
??????//如果服務器已經啟動則退出系統
??????System.exit(0);
????}?catch?(Exception?e)?{}//未做處理
????//如果服務器未啟動則在新的線程中啟動服務器
????(thread?=?new?Thread(new?Server())).setDaemon(true);
????//開始線程
????thread.start();
????//啟動主程序
????frame?=?new?JFrame("學海無涯");
????frame.setVisible(true);
??}
??/**
??*?端口監聽服務器端運行
??*?@author?hiswing
??*/
??static?class?Server?implements?Runnable?{
????public?final?void?run()?{
??????ServerSocket?serversocket?=?null;
??????//查找沒有占用的端口
??????while?(iPort?<?60000)?{
????????try{
??????????serversocket?=?new?ServerSocket(iPort);
????????}catch(Exception?ex){
??????????iPort++;
????????}
????????break;
??????}
??????try?{
????????do?{
??????????//監聽客戶端是否有連接
??????????serversocket.accept();
??????????//窗口在任務欄閃動
??????????if(frame.getExtendedState()?==?1)?{
????????????frame.setExtendedState(0);
??????????}
??????????if(frame.getExtendedState()?!=?1)?{
????????????frame.toFront();
????????????frame.requestFocus();
????????????frame.repaint();
??????????}
????????}?while(true);
??????}?catch?(Exception?ex)?{
????????//不做處理
??????}
????}
??}
}
由于沒有好的思路,使我們在編程中走了許多彎路,浪費了寶貴的時間。都說軟件是智慧的結晶,一點沒錯。