許多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文件中保存的數據進行比較。如果兩個記錄匹配,那么這張選票就是有效的。如果這兩個記錄不能匹配,那么這張選票就不會被核實。相反,會生成一個新的電子郵件確認,其中包含數據庫中的一條新驗證記錄。這將覆蓋對應電子郵件地址的預選票項,從而有效地從頭再次處理選票。
如果這兩條記錄可以匹配,那么投票者就可以確認預選票?,F在,如果投票者改變了注意,那么他可以只返回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上的連接請求??蛻魴C(投票者)通常可以從一個知名的靜態地址(例如學校提供的主頁)上的鏈接重定向到投票服務器上。在投票完成之后,提供Web服務的服務器就可以從Web上完全消失了,無需關閉或重新配置這臺服務器。其中并沒有任何缺點可以影響到所引用的頁面(這臺服務器是由其他人進行管理的)。在一些對政策敏感的環境中,這種考慮尤其重要。(有關使用動態DNS的更詳細內容,請參閱將傳入的所有意料之外字符的所有變量都轉換成字符串,并將其截斷為合理的限制長度。 腳本中保存了很多運行時數據。這樣做的優點是不需要部署很多的文件,并設置它們的權限。缺點是用戶可能不想編輯代碼,代碼變得更加不夠清晰。一種折衷的方法是利用諸如DATA
偽文件句柄之類的不完善系統在腳本的末尾保存數據。 文件加鎖是一個非常棘手的問題,很多時候都存在競爭條件??雌饋砦宜业降娜魏我环N所謂的文件加鎖的正確指南,之后又都進行了更新。我試圖最大限度地縮短打開文件的時間,并充分利用為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网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91精品国产综合久久男男|
欧美国产日韩二区|
国产成人精品在线观看|
国产精品综合不卡av|
日韩免费高清在线观看|
y97精品国产97久久久久久|
久久久噜噜噜久噜久久|
成人性教育视频在线观看|
上原亚衣av一区二区三区|
国产精品第3页|
欧美日韩另类字幕中文|
国产精品免费久久久久久|
欧美激情精品久久久久久久变态|
日韩免费在线播放|
日韩欧美国产激情|
久久人人爽人人|
国产精品久久久久久中文字|
9.1国产丝袜在线观看|
成人在线观看视频网站|
欧美在线www|
亚洲成**性毛茸茸|
97超视频免费观看|
45www国产精品网站|
亚州成人av在线|
欧美插天视频在线播放|
欧美激情喷水视频|
91国产美女在线观看|
亚洲欧美国产一本综合首页|
亚洲高清久久久久久|
日韩成人在线网站|
亚洲欧美综合v|
国产99久久精品一区二区 夜夜躁日日躁|
xxxxx91麻豆|
久久精品国产一区二区三区|
51色欧美片视频在线观看|
裸体女人亚洲精品一区|
国内精品模特av私拍在线观看|
国产亚洲精品久久久优势|
国产亚洲精品久久久久动|
日韩av在线天堂网|
亚洲精品乱码久久久久久按摩观|
日韩精品免费在线|
国产精品美女主播在线观看纯欲|
欧洲中文字幕国产精品|
久久免费观看视频|
国产一区二区在线免费视频|
欧美野外wwwxxx|
久久久av亚洲男天堂|
另类少妇人与禽zozz0性伦|
成人福利视频在线观看|
亚洲第一中文字幕|
**欧美日韩vr在线|
精品国产91乱高清在线观看|
亚洲精品456在线播放狼人|
欧美一级视频免费在线观看|
国产成人欧美在线观看|
欧美成人合集magnet|
欧美成人精品不卡视频在线观看|
国产美女直播视频一区|
久久69精品久久久久久国产越南|
日本成人精品在线|
国产91在线播放精品91|
国产成人精彩在线视频九色|
欧美性猛交xxxx黑人猛交|
两个人的视频www国产精品|
久久久国产在线视频|
精品久久久久久久大神国产|
国产成人精品999|
91精品美女在线|
久久69精品久久久久久久电影好|
米奇精品一区二区三区在线观看|
成人激情在线观看|
亚洲男人的天堂在线播放|
97在线视频精品|
国产成人亚洲综合91|
黄网动漫久久久|
欧美日本高清一区|
日韩中文字幕精品|
久久激情五月丁香伊人|
精品在线欧美视频|
国产一区二区美女视频|
亚洲综合视频1区|
久久999免费视频|
欧美一级片一区|
欧美日韩亚洲国产一区|
亚洲91精品在线观看|
国产精品一区二区三区在线播放|
亚洲国产精品成人一区二区|
久久夜精品va视频免费观看|
国产精品久久久久久久久影视|
国产精品中文久久久久久久|
欧美亚洲第一页|
在线激情影院一区|
日韩的一区二区|
成人一区二区电影|
久久精品亚洲国产|
日日狠狠久久偷偷四色综合免费|
精品国产福利视频|
亚洲全黄一级网站|
色噜噜国产精品视频一区二区|
欧美二区乱c黑人|
亚洲欧美日韩在线高清直播|
亚洲第一色在线|
最近2019年手机中文字幕|
在线观看国产成人av片|
国产一区二区三区免费视频|
日韩av中文字幕在线|
日韩高清av一区二区三区|
色婷婷av一区二区三区在线观看|
亚洲综合第一页|
欧美成人免费在线视频|
欧美日韩国产va另类|
96精品视频在线|
91在线视频成人|
亚洲深夜福利网站|
一色桃子一区二区|
久久久免费观看视频|
国产亚洲美女久久|
亚洲精品成人免费|
日韩免费av一区二区|
国内精品久久久久久|
国产精品久久一|
亚洲人成电影网|
一夜七次郎国产精品亚洲|
午夜美女久久久久爽久久|
午夜精品久久久久久久99黑人|
91久久久久久久久久久久久|
庆余年2免费日韩剧观看大牛|
美女精品久久久|
亚洲欧美中文字幕在线一区|
国产视频亚洲精品|
欧美巨猛xxxx猛交黑人97人|
欧美精品情趣视频|
亚洲性线免费观看视频成熟|
国产精品视频xxx|
亚洲人成啪啪网站|
欧美激情啊啊啊|
亚洲变态欧美另类捆绑|
国内精品久久久久久中文字幕|
久久久国产精彩视频美女艺术照福利|
国产专区精品视频|
久久久久亚洲精品国产|
国产成人一区二|
久久久亚洲国产天美传媒修理工|
最新国产精品亚洲|
欧美精品电影免费在线观看|
久久久久www|
亚洲成年人在线播放|
欧美一区二三区|
久久久久久久久网站|
欧美国产日韩中文字幕在线|
另类色图亚洲色图|
91久久精品国产91久久|
欧美福利在线观看|
精品国产依人香蕉在线精品|
日韩美女中文字幕|
在线丨暗呦小u女国产精品|
日韩精品电影网|
操人视频在线观看欧美|
亚洲成人久久久久|
亚洲最大的网站|
日韩视频在线免费观看|
美女国内精品自产拍在线播放|
亚洲自拍偷拍区|