許多Web部署的應用程序都是在精心設計的數據庫驅動的服務器端開發框架中編寫的,例如php和java™servlet,但是對于一些簡單的程序(例如,整個數據庫要能夠存放在Web服務器的RAM中)來說,使用加鎖的DMB文件和Perl MLDBM
模塊可以很容易地實現數據持久性。本文將給出一個基于Web的投票系統的真實的例子,重點介紹如何利用最小的外部模塊、如何舍棄基于客戶機的cookie以及如何利用CGI屬性的優點。
軟件正日益變得更加復雜,這并不是什么秘密;我們也看到一些額外的層次被添加到系統中,以保持軟件組件的模塊化。最重要的結果是,這些系統現在更易于維護,而且可擴展性也更好;但是有時這些技術有過多的重復,會導致軟件的過度設計。在另外一些情況下,開發開發人員寧愿選擇一些過度復雜但卻非常有名的技術,也不愿意集成一些簡單但卻不太熟悉的技術。
不管怎樣,如果所有人都有一把錘子,那么每個問題看起來都不過像一顆釘子而已。
我最近被請求為一所大學的學生組織設計一個小程序,以統計選舉票數。這是一個非常簡單的項目,每周處理的學生請求不會超過500個;之后該程序會立即統計并發布結果。
由于這個項目對服務級別的要求很低,因此使用一個外部數據庫來處理查詢并沒有什么好處。相反,使用腳本可以直接快速讀寫數據結構。不過,我仍然希望能夠將一些經過良好設計的功能封裝在一起,而不是采用一些像意大利面那樣,將雜亂的代碼拼裝在一起。我希望可以采用一個經過仔細考慮的自成體系的設計,該設計將提供一些簡化的部署。
對于底層架構來說,CGI(CommonGatewayInterface)是第一種廣泛用來擴展Web服務器從而提供交互內容的方法。開發人員通常會鼓吹一些新的標準,例如jsp、.NET、mod_perl、PHP和ISAPI,這些技術也的確可以彌補CGI的一些不足。但是在這個項目中,我們只需要對幾百個用戶計算投票數,這樣一個CGI腳本很難構成一個大型的應用程序,因為所有的投票信息都可以放到Web服務器的系統RAM中。在用戶每次提交一個讀寫數據的請求時,這可以將要查詢的整個表裝入內存中。
還有,通過將邏輯數據分隔成3個不同的物理文件,可以實現填寫選票、確認選票和統計結果的邏輯順序;這樣做可以最大限度地減少打開已加鎖的文件。
如果一個事務在很偶然的情況下因為加鎖的文件而失敗了,那么這并不會產生實際的問題。不管一個事務是由于網絡問題還是加鎖文件而失敗的,結果都是相同的:用戶只需再等待一會兒即可,選票隨后很有可能對其中的一次嘗試進行統計。我們應該記住這種行為,然而,對于不同的應用程序來說,情況并非總是如此,因此可能無法處理并發事務。
對于這個項目來說,CGI提供了以下幾個優點:
然而,需要記住的是,由于平臺的限制,CGI程序(它們會創建一些新的進程)在Win32的系統上運行速度非常慢。此外,盡管ApacheWeb服務器已經可以在Windows®上運行得很好,但是它依然被認為是一個linux™/UNIX®系統上的程序。參考資料部分提供了有關在Win32系統上可以使用的其他(非IIS)Web服務器的信息,在最初的NationalCenterforSupercomputingapplications(NCSA)站點上,還提供了一份CGI規范的經典介紹。
現在讓我們立即開始考慮這個簡單項目的主要問題:功能設計。
以下是我們的一些考慮。開始的時候,用戶面前會出現一個屏幕,要求輸入用戶自己的電子郵件地址,并從一個Web表單中選擇幾個候選人。選中候選人后就可以提交他們,結果會記錄在本地的一個預選票中。然后,會向提供的電子郵件發送一個電子郵件確認。在這種情況中,我們假設一個經過驗證的電子郵件地址就足以建立用戶的身份。
這樣會出現多次投票的問題。從實踐角度來說,我想我們沒有什么辦法限制一個用戶使用多個電子郵件地址進行多次投票,但是我們可以對選票進行限制,只允許一個電子郵件帳號投一票。這個電子郵件的驗證中包含一個鏈接,它指向原來的CGI腳本,這樣就可以將該鏈接與本地DBM文件中保存的數據進行比較。如果兩個記錄匹配,那么這張選票就是有效的。如果這兩個記錄不能匹配,那么這張選票就不會被核實。相反,會生成一個新的電子郵件確認,其中包含數據庫中的一條新驗證記錄。這將覆蓋對應電子郵件地址的預選票項,從而有效地從頭再次處理選票。
如果這兩條記錄可以匹配,那么投票者就可以確認預選票。現在,如果投票者改變了注意,那么他可以只返回Web表單,并輸入一個新的預選票,替換原來的預選票。這種設計可以得到一個比較安全的系統;條件是每個投票的用戶都有且只有一個可以接受的電子郵件帳號,這樣就可以保證每個用戶都不會投兩次票。(稍后我會回到這個問題上。)
現在讓我們開始詳細介紹系統的細節。
在Perl中,可以使用哈希鍵值來創建聯合數組,從而使我們能夠動態開發復雜的數據結構。當您將這種特性與將這些(任意復雜的)數據結構保存在二進制DBM文件中的能力結合在一起使用時,就可以開發出一個小型的數據庫系統。完成這些工作所缺少的組件可以由MLDBM
和MLDBM::Sync
模塊提供。
MLDBM
模塊可以將復雜的Perl哈希鍵值無縫地保存在一個本地文件中。MLDBM::Sync
模塊使得對這些文件進行安全加鎖成為可能,它使用了$sync->Lock
和$sync->ReadLock
方法。在加載或保存所需要的結構之后,再調用UnLock()
方法來刷新I/O并釋放變量。(關于這方面的更多信息,請參閱Perl文檔中有關MLDBM::Sync
模塊的內容:man3MLDBM::Sync
。)
從根本上來說,邏輯流程非常簡單,如清單1所示。
1unless(defined($q->param($vparm))){2#Displayinitialvotingstuffhere3#selectacandidate4$ballotBox->變量和MLDBM
文家鎖定來檢索和更新所需的哈希數據結構。所使用的對象更像是一些精巧的數據結構,而不像是一些羽翼豐滿的對象;在這些對象之間,數據是以某種并行方式處理的:選票也從最初的預選票轉換成為最終的正式選票。換言之,選票清單被用來構建一個DraftBallot
,而這個DraftBallot
又被用來創建CastBallot
和BallotBox
類。這樣,對于主要的投票CGI程序,耦合性就是最小的。
從另外一方面來說,雖然我通常認為使用一些依賴于外部資源(例如文件)的構造函數不是一個好的實踐方法(因為這樣可能會引起失敗,并導致一些不可預知的狀態),但是在這種情況下,以這種方式實現的代碼將更易于理解。由于Perl并不依賴于指針,所以沒什么理由不利用這種簡單性。
細節:電子郵件
允許用戶從您的Web服務器上發送電子郵件是一個危險的舉動,因為垃圾郵件可以利用您的主機來胡亂發送電子郵件。為了將這種威脅降至最低,腳本通常會檢查要發送的電子郵件地址是否是一個可到達的地址。您可以通過修改DraftBallot
類中的驗證方法voter_is_okay()
來加強這種限制,使其在進行驗證時參考一個可接受的電子郵件地址。這樣可能會要求用戶在進行投票之前進行注冊。防止出現重復投票的其他方法包括搜集只監聽localhost的地址。然后,通過單擊一個之前提交的鏈接,可以將完整的結果回顯給所有用戶,并且可以通過向一個專用的免費電子郵件帳號發送一個副本,來收集完整的結果。
注意,在這個例子下,每個選票都不會被統計兩次。在那些確定需要保密的情況中,可以使用一個簡短的Javascript函數來隱藏結果。誠然,有些人可能希望完全采用匿名投票,但是由于俱樂部的選舉通常都是通過舉手表決的,因此這很難實現安全的投票。
在考慮這種工作流程模式時,我意識到使用基于GET
的驗證鏈接以及使用非加密驗證鏈接的必要性,這樣可以進行一些實驗,讀取這些鏈接,并基于指定的電子郵件地址和一些已知的驗證鏈接來構建一些錯誤的確認投票。為了防止這種事情的發生,同時為了仍然能夠通過非加密鏈接進行簡單的調試,我決定在驗證步驟中添加一、兩項內容:為每個預選票添加一個惟一的標識符。
這個標識符是基于操作系統中正在執行的腳本的集成標識符(PID)的。為了讓預測驗證預選票的URL更加困難,我們可以再使用一個隨機數。我之所以關心這個問題,是因為會有一些惡意的用戶可能會對非常直觀的URL模式進行破解,從而試圖構建一些虛假的驗證選票。這是代碼的一部分,它不會直接轉換為一個mod_perl
版本,因為它要依賴于正在運行的Perl的PID,以及另外一個隨機數。如果這個表單是從一個重用的mod_perl
實例中生成的,那么在兩次調用之間,PID可能并不需要改變。
然后,我又意識到能使這個鏈接更具迷惑性的方法是使用一個md5生成的哈希值,從而有效地隱藏所有投票者的信息。這具有雙向受益的優點:既可以使它很難被偽造,同時還維護了基于mod_perl
的腳本的可移植能力。缺點是代碼有些難以調試,因為需要對客戶機與服務器之間交換的信息進行監視。
細節:文件布局
安裝過程要求Web服務器上有三種類型的目錄:
一個可寫的目錄,用來保存用戶提交的選票。 一個位置,CGI需要在這里運行。 一個位置,用來保存靜態數據(例如CSS,logo圖像,以及包含更詳細指令的文件)。 還要注意的是,這種權限可以進行修改,這樣,Web服務器就可以向這個目錄中寫入DBM文件的內容了。
清單2顯示了在Web服務器上創建典型目錄的過程。
清單2.在Web服務器上設置目錄
$iduid=500(allan)gid=500(allan)groups=10(wheel),48(apache),500(allan)$sudomkdir/var/www/db/var/www/javascript//var/www/css/$sudochmod2775/var/www/db$sudochmod2755/var/www/javascript//var/www/css/$sudochownapache.apache/var/www/db/
嚴格來說,只有cgi-bin(/var/www/cgi-bin)和DBM(/var/www/db)目錄是絕對必需的,因為它們分別保存了腳本的可執行文件和投票數據。清單1中給出的文件布局是專用于Linux的,Web服務器進程的用戶和組名可能有所不同,但實質上都需要在文件系統的適當地方放上幾個Web服務器可以訪問的組件。在將支持文件復制到各自的目錄中之后,要確保對Web服務器的配置文件(例如httpd.conf)中的別名進行了正確更新。
在創建清單2中所給出的目錄之后,將ZIP文件中展開的內容復制到您的系統的類似目錄中。其中最重要的是,ballot、DraftBallot.pm、BallotBox.pm和CastBallot.pm文件都需要位于cgi-bin目錄中。我們只需要使用3個非標準的Perl模塊;安裝過程如清單3所示(更詳細的信息,請參閱模塊的README文件)。
清單3.安裝Perl模塊
$sudoperl-MCPAN-e'installMLDBM'$sudoperl-MCPAN-e'installMLDBM::Sync'$sudoperl-MCPAN-e'installMIME::Lite'
細節:靜態DNS與動態DNS
雖然我可以用一個靜態IP地址在擁有已分配的域的站點中建立這種服務,但是我覺得動態DNS應該可以提供一些安全上的好處。通常,如果一個服務器沒有靜態IP地址,那么來自Web上的訪問流量就不可能太大,動態DNS讓我們可以在另外一個頂級域名之上臨時建立一個可解析的機器名。這樣我們就可以在Internet上快速出現,并快速消失,將遭受黑客攻擊的風險降至最低。最好的方法是,這種服務是免費的。
還需要指出的是,將服務器配置為監聽一個非標準的大一些的端口(例如8000)是很明智的,因為很多ISP都阻塞了端口80上的連接請求。客戶機(投票者)通常可以從一個知名的靜態地址(例如學校提供的主頁)上的鏈接重定向到投票服務器上。在投票完成之后,提供Web服務的服務器就可以從Web上完全消失了,無需關閉或重新配置這臺服務器。其中并沒有任何缺點可以影響到所引用的頁面(這臺服務器是由其他人進行管理的)。在一些對政策敏感的環境中,這種考慮尤其重要。(有關使用動態DNS的更詳細內容,請參閱將傳入的所有意料之外字符的所有變量都轉換成字符串,并將其截斷為合理的限制長度。 腳本中保存了很多運行時數據。這樣做的優點是不需要部署很多的文件,并設置它們的權限。缺點是用戶可能不想編輯代碼,代碼變得更加不夠清晰。一種折衷的方法是利用諸如DATA
偽文件句柄之類的不完善系統在腳本的末尾保存數據。 文件加鎖是一個非常棘手的問題,很多時候都存在競爭條件。看起來我所找到的任何一種所謂的文件加鎖的正確指南,之后又都進行了更新。我試圖最大限度地縮短打開文件的時間,并充分利用為MLDBM
模塊提供的機制。 Perl模塊并沒有放到CGI之外自己的路徑中,因此從理論上來說,我們只能在cgi-bin目錄中執行它。建議我們不要將這些模塊設置為可執行的。 PHP是Linux平臺上廣泛存在的一種工具,因此如果需要重新實現這個系統,我考慮將這個腳本移植到PHP中。然而,我不確定是否有一個與MLDBM
模塊等效的PHP模塊。 有些人認為投票表單的布局不合理,因為第一個候選人是默認值。 我沒有使用perldoc,我本來應該使用它的。 結束語
假如有機會構建一個這樣的系統,同時試著保持它的簡單性并使其自成一體,那么該系統可以使我能夠研究一些非常有用的Perl模塊。我發現為這樣一個簡單的項目定義特性和開發功能規范的過程既很有趣又是一種享受。我希望本文中在構建這種系統時的一些考慮事項可以為您實現類似的項目提供一些幫助。
學習交流
熱門圖片
猜你喜歡的新聞
新聞熱點
2019-10-23 09:17:05
2019-10-21 09:20:02
2019-10-21 09:00:12
2019-09-26 08:57:12
2019-09-25 08:46:36
2019-09-25 08:15:43
疑難解答
圖片精選
主站蜘蛛池模板:
精品国产乱码久久久久久闺蜜
|
久久av网
|
日韩精品一区二区三区免费视频
|
av电影网在线观看
|
精品人伦一区二区三区蜜桃视频
|
香蕉婷婷
|
久久久久久久国产精品
|
国产精品久久久久国产a级
久久国产精品精品
|
二区在线视频
|
日韩精品1区2区3区
99久久视频
|
色婷婷综合国产精品一区
|
中文字幕自拍偷拍
|
国产午夜手机精彩视频
|
91中文字幕在线观看
|
国产精品视频1区
|
日本一二区视频
|
成人av电影免费看
|
成人综合区
|
日韩免费在线观看视频
|
岛国av在线
|
成人黄色精品
|
国产精品多久久久久久情趣酒店
|
精品久久国产
|
久久精品免费视频观看
|
国产成人免费视频网站视频社区
|
国产l精品国产亚洲区久久
国产suv精品一区
|
日韩免费不卡视频
|
欧美与黑人午夜性猛交
|
欧美在线国产
|
欧美日韩国语
|
国产成人一区二区三区影院在线
|
黄色一级影视
|
99精品亚洲
|
美女一区二区三区在线观看
|
亚洲精品白浆高清久久久久久
|
在线免费观看色视频
|
在线高清av
|
青青草亚洲
|
久久在线视频
|
黄片毛片
|
日韩毛片
|