摘 要: 利用ActiveX控件技術(shù),結(jié)合B/S模式與C/S模式的雙重優(yōu)點,將C/S模式中的socket網(wǎng)絡(luò)通信技術(shù)移植于B/S模式中,,實現(xiàn)單態(tài)模式登錄,為基于B/S模式應(yīng)用系統(tǒng)的客戶端與服務(wù)器的通信提供了一種新的解決方案,。
關(guān)鍵詞: 單態(tài),; B/S模式; C/S模式,; ActiveX組件
單態(tài)(Singleton)模式的主要作用是使得一個類Class只有一個實例存在,,即該模式僅允許有且僅有一個實例在運行。在很多C/S模式的軟件中經(jīng)常會遇到單態(tài)模式的應(yīng)用,。用戶用一個賬號登錄系統(tǒng)之后,,如果想再用第二個賬號登錄,必須先把第一個賬號注銷,。該模式在C/S模式中實現(xiàn)比較簡單,,但在B/S模式中實現(xiàn)卻比較復(fù)雜。在B/S模式中,,瀏覽器本身并不是單態(tài)模式,,用戶可以打開多個瀏覽器來登錄同一個系統(tǒng),例如在瀏覽器的實例1中用“張三”登錄,,再打開瀏覽器的實例2,,用“李四”登錄,,這時雖然是用兩個瀏覽器實例在系統(tǒng)中登錄了兩個賬號,但這兩個實例之間會相互影響,,特別是與服務(wù)器通信時,,容易帶來通信對象錯誤的問題。
B/S模式程序中一般會采用Session或cookie來保存登錄信息,,便于在其他的頁面中使用,,以避免多次重復(fù)登錄系統(tǒng),,即所謂的單點登錄(SSO)模式,。在前面所舉的例子中,用“張三”登錄后,,可將其保存在session中,,令Session[‘username’]=“張三”;如果再用“李四”登錄,,同樣也可保存在Session中,,Session[‘username’]=“李四”;由于系統(tǒng)中的Session是唯一的,,所以這時Session[‘username’]會覆蓋前面的值,,使得在用“張三”登錄的系統(tǒng)中實際保存的登錄信息變成了“李四”。
1 單態(tài)登錄模式功能
本文所提到的單態(tài)登錄模式擬實現(xiàn)以下功能:
(1) 在一臺機器上只能登錄一個賬號,,如果已經(jīng)登錄了一個賬號,,再次登錄時則提示登錄失敗。
(2) 一個賬號最多只能在一臺機器上登錄,,如果要登錄的賬號已在其他的機器上登錄了,則提示登錄失敗,。
實現(xiàn)此項功能的好處之一是在客戶端與服務(wù)器進行通信時,在查找通信對象時不至于發(fā)生錯誤,。
單態(tài)模式登錄在C/S模式中可以采用很多方法來實現(xiàn)上述功能,但在B/S模式中實現(xiàn)起來卻比較困難,。最簡單的方法是在數(shù)據(jù)庫中建一個數(shù)據(jù)表Login(字段為UserName和LoginIP),用來保存已登錄的登錄賬號和登錄機器的IP信息。每次登錄時,,先查一下該數(shù)據(jù)表,,確定要登錄的賬號在Login表中是否已存在,如果不存在則表明該賬號尚未登錄,,允許登錄,;如果存在則表明已被登錄,不可再登錄,。退出系統(tǒng)時,,先將Login表中對應(yīng)的記錄刪除掉。
該方法存在的最大問題是:當?shù)卿浵到y(tǒng)后,,若出現(xiàn)非正常退出系統(tǒng)的情況(如突然斷電,、程序崩潰等),,則無法將Login表中的記錄清除。使得下次登錄查詢Login表時,,誤以為該賬號仍在登錄中,,導(dǎo)致登錄失敗。
有人提出每隔一定時間(如30 s)查詢Session來判斷用戶是否在線,,這種方法一方面不能保證百分之百地解決問題,,另一方面會給服務(wù)器帶來不小的負擔。本文所給出的B/S模式的單態(tài)模式登錄方法是利用ActiveX技術(shù)結(jié)合C/S模式與B/S模式的特點,,在ActiveX控件中運用網(wǎng)絡(luò)通信技術(shù)來解決前面所提到的問題,。
2 關(guān)鍵技術(shù)
ActiveX是微軟提出的采用COM(Component Object Model)和DCOM(Distributed Component Object Model)使軟件組件在網(wǎng)絡(luò)環(huán)境中進行交互的一組技術(shù)集,它是在COM之上建立的一種理論和概念,,與具體的編程語言無關(guān),,包括ActiveX Dll組件和ActiveX控件。
本文采用的方法是ActiveX控件,。在ActiveX控件中,,運用socket網(wǎng)絡(luò)通信技術(shù)實現(xiàn)客戶端與服務(wù)器之間的通信,或者客戶端與客戶端之間的直接通信,。用戶可在不安裝客戶端程序的情況下直接通過瀏覽器與服務(wù)器或其他客戶端進行通信,。Activex控件可直接嵌入Web頁面,在Web頁面中通過<object>標簽來創(chuàng)建,,
<object>標簽包含控件的類ID(CLSID),,用于識別需要實例化的ActiveX控件,<object>標簽中也可指定控件的CodeBase屬性值,,供用戶查找和自動下載該控件并在本地注冊,,訪問和控制遠程服務(wù)器的數(shù)據(jù):如下面代碼所示:
<object id= "SendCtr" width=0 height=0
classid="clsid:6571016D-39C4-47AB-9425-9995F68AABE4" codebase="SendMsg.CAB"></object>。
控件技術(shù)的具體實現(xiàn)過程為:當瀏覽器發(fā)出請求時,,Web服務(wù)器向用戶瀏覽器回傳內(nèi)嵌ActiveX控件的頁面,,由瀏覽器負責解釋。在解釋過程中首先用該控件在頁面中注明的ID值,,在本地的注冊表內(nèi)進行查詢,,若已經(jīng)存在,則說明該控件已經(jīng)在本地安裝,,然后通過注冊表中的相關(guān)信息直接使用該控件,;否則就要根據(jù)頁面中所提示的該控件所在的服務(wù)器上的路徑到服務(wù)器上下載并且自動完成在本地的安裝注冊,使該控件成為本地資源,,供以后使用,。當Web服務(wù)器提供更高版本的ActiveX控件時,瀏覽器會自動下載新的控件,并自動安裝,,覆蓋原來的控件,。控件提供了接口方法,,可以在頁面中用JavaScript腳本語言來調(diào)用,,如:
document.getElementById("SendCtr").Send(“192.168.
0.13”,”Hello!”);
此處調(diào)用的是SendCtr控件的Send方法,用于向IP為“192.168.0.13”發(fā)送消息”Hello!”,。
3 實現(xiàn)原理
要實現(xiàn)網(wǎng)絡(luò)通信的功能,可在頁面中加入兩個activex控件:SendMsg和RecvMsg,一個用于發(fā)送消息,,另一個用于接收消息。SendMsg控件放在登錄頁面中,RecvMsg控件放在登錄后的用戶操作界面中,每次登錄時,,如果發(fā)現(xiàn)要登錄的賬號在Login表中已經(jīng)存在,,則先由SendMsg控件檢測目的賬號是否在線,如果檢測出不在線,,說明該賬號是上次登錄后非正常退出了,,使得Login表沒有及時刪除該條記錄,,所以先將該記錄刪除掉,,再將本次登錄的記錄插入Login 表中;如果檢測到對方在線,,則提示該賬號已被人登錄了,,本次登錄失敗,可由邏輯流程圖(如圖1)實現(xiàn)上面提到的兩個功能(設(shè)登錄賬號為zhangsan,本機IP為192.168.0.13),。
4 核心代碼
在SendMsg控件中,提供了一個接口函數(shù):CheckIsOnLine(LPCTSTR strDestIP),。該接口函數(shù)僅有一個參數(shù)strDestIP,即要檢測是否在線的目的IP,。該函數(shù)用來檢測目的IP上的系統(tǒng)是否在線,,實現(xiàn)的原理也較簡單:給該IP發(fā)送一個消息,如果在規(guī)定時間內(nèi)收到回復(fù),,則說明對方在線,,因為只有其在線,才能在登錄后的用戶界面中用RecvMsg控件回復(fù)消息,。CheckIsOnLine內(nèi)部實現(xiàn)主要源碼如下:
CheckIsOnLine(LPCTSTR strDestIP)
{
char msg[10];
strcpy_s(msg,".");
sockaddr_in checkaddr;
checkaddr.sin_family = AF_INET;
checkaddr.sin_addr.S_un.S_addr = inet_addr(strDestIP);
checkaddr.sin_port = htons(5002);
//連接目的客戶端,向目的客戶端發(fā)送信息".",,看有無回復(fù)
sendto(m_Socket,msg,10,0,(sockaddr*)&checkaddr,sizeof
(checkaddr));
fd_set rfd;
FD_ZERO(&rfd);
FD_SET(skt,&rfd);
timeval time;
time.tv_sec = 0;
time.tv_usec = 500;
int iResult = select(0,&rfd,NULL,NULL,&time);
//檢測在500 ms內(nèi)有無回信
if(!iResult) //對方?jīng)]有回信
{CString strSql = "delete Login where LoginIP =′"+ strDestIP +"′";
m_Ado.CmdExcute(strSql,FALSE);
//將Login表中數(shù)據(jù)刪除
}
else
{ char* pData = new char[1024];
memset(pData,0,1024);
sockaddr_in addr;
int factsize = sizeof(sockaddr);
int ret =recvfrom(m_Socket,pData,1024,0,(sockaddr*)&addr,&factsize);
if (ret > 0) //對方在線,提示登錄失敗
{
MessageBox("該用戶已登錄且尚未退出系統(tǒng),登錄失??!","提示");
}
}
}
在RecvMsg控件中只需在接受消息時,判斷消息如果為".",回復(fù)一個消息即可,。
本文所給出的方法已在Windows XP系統(tǒng),、ASP.net3.5、IE7.0環(huán)境下測試通過。利用該方法也可以實現(xiàn)WebQQ的即時通信功能,。利用Activex組件技術(shù),,可以很好地發(fā)揮B/S模式與C/S模式的雙重優(yōu)點,采用混合工作模式及合理的功能配制,,克服單一的B/S模式或單一C/S模式安全與效率,、功能與應(yīng)用的多種矛盾與不足,為開發(fā)一個完善的應(yīng)用系統(tǒng)提供借鑒,。將ActiveX技術(shù)應(yīng)用于B/S監(jiān)控軟件中,,不僅增強了B/S監(jiān)控軟件的功能,加快了軟件的開發(fā)速度,,而且適應(yīng)了當前軟件開發(fā)向模塊化,、開放化發(fā)展的趨勢,提高了系統(tǒng)的實時性,、可靠性和可擴展性,。ActiveX技術(shù)應(yīng)用于B/S模式彌補了單B/S模式的不足,比B/S和C/S結(jié)合的方式簡單實用(不需要安裝C/S客戶端),,可以用在商業(yè)化的在線殺毒,、在線點播、在線考試等諸多領(lǐng)域,,具有較大的應(yīng)用參考價值,。
參考文獻
[1] 鄭健,庖丁解牛.縱向切入ASP.NET 3.5控件和組件開發(fā)技術(shù)(第一版)[M].北京:電子工業(yè)出版社,2009.
[2] (美)伊夫杰等. ASP.NET 3.5高級編程(第5版)[M].北京:清華大學出版社,2008.
[3] (美)杰瑞夫(Jeffrey, J.)等. Windows核心編程(第5版)[M].北京:清華大學出版社,2008.
[4] (美) 維埃拉,,董明.SQL Server 2005高級程序設(shè)計(第一版)[M].北京:人民郵電出版社,2008.