劉睿,任曉慧,于波
(聊城大學(xué)計(jì)算機(jī)學(xué)院,聊城252000)
當(dāng)代社會(huì)步入一個(gè)高速發(fā)展的時(shí)代,科技發(fā)達(dá)、信息流通,人們之間的交流越來(lái)越密切,信息資源也成為國(guó)家發(fā)展、社會(huì)進(jìn)步的重要戰(zhàn)略資源,信息的傳播與分享成為創(chuàng)造效率的必要條件。文件作為互聯(lián)網(wǎng)信息傳輸常用載體之一,其分發(fā)傳輸在內(nèi)容分發(fā)網(wǎng)絡(luò)、P2P 網(wǎng)絡(luò)等方面都有比較成熟的研究和應(yīng)用成果。而在日常教學(xué)及工作中,經(jīng)常需要將規(guī)模小的信息以文件的方式快速分發(fā)出去,距離近(如位于同一局域網(wǎng)中的辦公室之間或者教室、機(jī)房?jī)?nèi)),如何提高工作效率以及辦公質(zhì)量是本文所設(shè)計(jì)文件共享方式的初衷。目前也有許多學(xué)者進(jìn)行過(guò)相關(guān)的研究,文獻(xiàn)[1]中研究實(shí)現(xiàn)了一種基于Python 語(yǔ)言的分布式文件共享系統(tǒng),本文同樣采用Python 語(yǔ)言編程,實(shí)現(xiàn)了分布式文件共享的功能,并在其基礎(chǔ)上進(jìn)行了優(yōu)化設(shè)計(jì):通過(guò)寫(xiě)入數(shù)據(jù)庫(kù)表的形式,實(shí)現(xiàn)對(duì)分享?xiàng)l目的動(dòng)態(tài)修改和對(duì)無(wú)效信息的及時(shí)清除,減少數(shù)據(jù)冗余;通過(guò)利用系統(tǒng)的體系監(jiān)控機(jī)制,實(shí)現(xiàn)針對(duì)常見(jiàn)系統(tǒng)平臺(tái)(包括Windows 及Linux等)的動(dòng)態(tài)監(jiān)控。最終可實(shí)現(xiàn):加入網(wǎng)絡(luò)環(huán)境中的每一個(gè)成員,都成為信息的發(fā)布者和分享者,快速分發(fā),提高工作效率。
在日常的辦公及學(xué)習(xí)時(shí),常見(jiàn)的文件共享方式一般有以下幾種[1]:通過(guò)現(xiàn)代商業(yè)辦公體系和一些即時(shí)通訊工具進(jìn)行傳輸;建立FTP 協(xié)議的服務(wù)器進(jìn)行文件共享;通過(guò)郵箱發(fā)送郵件的形式;使用存儲(chǔ)設(shè)備拷貝共享等。這些傳輸方式類(lèi)型多樣,各有利弊,但共同點(diǎn)是都借用了第三方工具,獲取效率有所影響。本文設(shè)計(jì)實(shí)現(xiàn)的分布式文件共享方式特點(diǎn)為:實(shí)時(shí)查看,實(shí)時(shí)下載,方便快捷。該共享方式將網(wǎng)絡(luò)中內(nèi)部成員需要傳遞的文件信息加入到共享系統(tǒng)中來(lái),要想獲得這些信息,其他客戶端只需以網(wǎng)頁(yè)的形式使用關(guān)鍵字搜索即可快速實(shí)現(xiàn)。
Peer-to-Peer(簡(jiǎn)稱P2P,即對(duì)等方式技術(shù))[2-3],是小型局域網(wǎng)常用的組網(wǎng)方式。其可以定義為:網(wǎng)絡(luò)的參與者共享他們所擁有的一部分硬件資源,這些共享資源通過(guò)網(wǎng)絡(luò)提供服務(wù)和內(nèi)容,能被其他對(duì)等節(jié)點(diǎn)(Peer)直接訪問(wèn)而無(wú)需經(jīng)過(guò)中間實(shí)體。在此網(wǎng)絡(luò)中的參與者既是資源、服務(wù)和內(nèi)容的提供者,又是資源、服務(wù)和內(nèi)容的獲取者。
本文所設(shè)計(jì)的P2P 文件共享方式屬于集中式P2P網(wǎng)絡(luò)共享方式[2]。Peer 同時(shí)具有Client 和Server 的特點(diǎn),可以直接通信和文件傳輸[4]。
選擇使用Python 語(yǔ)言進(jìn)行服務(wù)器端、客戶端程序設(shè)計(jì),是因?yàn)镻ython 語(yǔ)言是一種語(yǔ)法簡(jiǎn)潔優(yōu)美、功能強(qiáng)大、應(yīng)用領(lǐng)域廣泛,具有強(qiáng)大完備的第三方庫(kù)的一種可移植、可擴(kuò)展、可嵌入的解釋型編程語(yǔ)言。Python 語(yǔ)言誕生于1990 年,由Guido van Rossum 設(shè)計(jì)并領(lǐng)導(dǎo)開(kāi)發(fā),目前是一種被廣泛使用的高級(jí)通用腳本編程語(yǔ)言[5-6]。它的特點(diǎn)是:語(yǔ)法簡(jiǎn)潔、與平臺(tái)無(wú)關(guān),有優(yōu)異的可擴(kuò)展性;Python 語(yǔ)言提供了豐富的內(nèi)置類(lèi)庫(kù)和函數(shù)庫(kù),可以大量利用已有的內(nèi)置或第三方代碼,能夠輕量級(jí)地完成各種任務(wù),用于編寫(xiě)各領(lǐng)域的應(yīng)用程序。Python 語(yǔ)言相對(duì)簡(jiǎn)潔、開(kāi)發(fā)效率高、易于維護(hù),目前已經(jīng)成為眾多科研領(lǐng)域使用的科學(xué)計(jì)算工具[7],具有廣闊的應(yīng)用空間。使用Python 語(yǔ)言進(jìn)行設(shè)計(jì),可充分享受其代碼簡(jiǎn)潔,語(yǔ)義容易理解的優(yōu)勢(shì),缺點(diǎn)在于運(yùn)行速度稍慢,代碼不能加密等,對(duì)于實(shí)用的小程序來(lái)講,此點(diǎn)可忽略。
本文系統(tǒng)的實(shí)現(xiàn)方式如下:在同一局域網(wǎng)或可以互相訪問(wèn)的虛擬局域網(wǎng)中,用戶通過(guò)運(yùn)行程序?qū)C 上用于分享的文件夾設(shè)置為共享,應(yīng)用程序?qū)⒅鲃?dòng)掃描該文件夾下所有文件,生成文件樹(shù)并提交到管理系統(tǒng)中,使用超文本傳輸協(xié)議(HTTP)的形式進(jìn)行共享和展示;對(duì)于文件搜索,由主機(jī)提供Web 程序,以網(wǎng)頁(yè)形式進(jìn)行交互式操作。其他網(wǎng)絡(luò)用戶可在智能終端使用通用的搜索入口進(jìn)行查詢,若能找到可根據(jù)需要進(jìn)行下載使用。為方便說(shuō)明,本文將所有使用本系統(tǒng)的電腦終端稱之為客戶端,負(fù)責(zé)承擔(dān)搜索任務(wù)的電腦終端稱為服務(wù)器端。服務(wù)器端承擔(dān)的搜索任務(wù)可以通過(guò)使用與客戶端相同的體系來(lái)實(shí)現(xiàn)。具體工作流程圖如圖1 所示。
圖1 總體流程圖
本文系統(tǒng)功能的實(shí)現(xiàn),分為客戶端、服務(wù)器端兩部分分別設(shè)計(jì)。
根據(jù)客戶端實(shí)現(xiàn)的功能,采用模塊化及逐層封裝思想,將文件操作,數(shù)據(jù)庫(kù)操作及網(wǎng)絡(luò)操作逐層封裝,具體分為以下幾個(gè)類(lèi)進(jìn)行功能實(shí)現(xiàn):FileTools 文件操作類(lèi)、DbTools 數(shù)據(jù)庫(kù)操作類(lèi)、Monitor 文件改動(dòng)監(jiān)控類(lèi)、ClionHttp 服務(wù)類(lèi)、Config 配置文件。作為與文獻(xiàn)[1]的比較,本文著重改進(jìn)的地方在于DbTools 數(shù)據(jù)庫(kù)操作類(lèi)與Monitor 文件改動(dòng)監(jiān)控類(lèi)兩部分的設(shè)計(jì),下面對(duì)每個(gè)功能類(lèi)的實(shí)現(xiàn)技術(shù)點(diǎn)進(jìn)行說(shuō)明。
按照系統(tǒng)設(shè)計(jì),客戶端需有能力獲取用戶設(shè)置為共享文件夾下的所有文件及路徑,故在文件操作類(lèi)FileTools 中實(shí)現(xiàn)獲取所有文件的方法,通過(guò)逐層遞歸遍歷實(shí)現(xiàn)所有文件的記錄,并同時(shí)記錄下文件所在具體位置。
for num in range(len(filelist)):
returndirstr +=creatfile.getfilelist(filepath + '/' + filelist[num])
if os.path.isdir(filepath+'/'+filelist[num]):
else:
returnfilestr+=filepath+'/'+filelist[num]+' '
returnstr+=returnfilestr+returndirstr
為了使文件的路徑信息轉(zhuǎn)換為對(duì)HTTP 服務(wù)的有效URL 路徑,故在文件操作類(lèi)中集成URL 轉(zhuǎn)換方法,實(shí)現(xiàn)由共享文件夾的相對(duì)位置轉(zhuǎn)化為Web 服務(wù)的有效路由信息:
list = list.replace(path, "http://" + str(ip)+ ':' + str(PORT)).spli(t' ')
通過(guò)Python 標(biāo)準(zhǔn)庫(kù)中字符串替換方法,高效生成HTTP 服務(wù)分享連接。同時(shí)為實(shí)現(xiàn)獲取客戶端IP 功能,使用UDP 報(bào)文頭抓取方法,該方法相比使用標(biāo)準(zhǔn)庫(kù)GETIP()等內(nèi)置功能的實(shí)現(xiàn)方法,更能高效地在客戶機(jī)用于兩個(gè)及以上IP 地址時(shí),自動(dòng)判別內(nèi)網(wǎng)IP,實(shí)現(xiàn)IP 定位功能。
針對(duì)客戶端所需的數(shù)據(jù)庫(kù)操縱能力,在比較多種實(shí)現(xiàn)技術(shù)后,使用對(duì)象關(guān)系映射技術(shù)(Object-Relational Mapping,ORM)[8],作為將本體(Ontology)文件存儲(chǔ)到關(guān)系型數(shù)據(jù)庫(kù)中的一種可借鑒的方法。通過(guò)在數(shù)據(jù)庫(kù)和代碼業(yè)務(wù)應(yīng)用層中間加入數(shù)據(jù)持久化層,避免直接對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作,避免如SQL 注入等常見(jiàn)的Web 攻擊方式,并且通過(guò)對(duì)數(shù)據(jù)域的對(duì)象化,可以方便的進(jìn)行面向?qū)ο蟮臄?shù)據(jù)元操作。將SQL 語(yǔ)句中的關(guān)系型聯(lián)系轉(zhuǎn)化為源類(lèi)對(duì)象之間的交互。
在具體的Python 語(yǔ)言中,類(lèi)似的ORM 框架有很多種[8][9],如SQLObject、Storm、Peewee 等。針對(duì)客戶端的特點(diǎn),選取Peewee 的Python ORM 框架,簡(jiǎn)單小巧,且容易學(xué)習(xí)。
由于客戶端向服務(wù)器端提交數(shù)據(jù),故設(shè)計(jì)數(shù)據(jù)庫(kù)表如下:
time 提交時(shí)間
ip 提交內(nèi)網(wǎng)IP name 文件名稱
filename http 分享連接
使用Peewee 建立數(shù)據(jù)表模型:
class ip_file_url(BaseModel):
time=CharField()
ip=CharField()
name=CharField()
filename=CharField(max_length=500)
針對(duì)客戶端具體功能要求,實(shí)現(xiàn)了對(duì)數(shù)據(jù)庫(kù)的增、刪功能。通過(guò)調(diào)用FILETOOLS 模塊獲得文件的名稱和HTTP 分享路徑,轉(zhuǎn)換成具體的數(shù)據(jù)庫(kù)條目,并調(diào)用Peewee 中的insert_many()方法,插入到服務(wù)器端數(shù)據(jù)表中。針對(duì)共享目錄下文件修改或文件增加、刪除問(wèn)題,統(tǒng)一使用數(shù)據(jù)表刪除方法,刪除掉本IP 提交的所有信息,并將新的文件共享項(xiàng)目表提交到服務(wù)器數(shù)據(jù)庫(kù)中。通過(guò)這種方法,來(lái)實(shí)現(xiàn)對(duì)共享?xiàng)l目的動(dòng)態(tài)修改和對(duì)無(wú)效信息的及時(shí)清除,減少數(shù)據(jù)冗余。
在文件分布式分揀存儲(chǔ)系統(tǒng)中,最重要的是實(shí)現(xiàn)文件信息的動(dòng)態(tài)更新。因?yàn)樵趯?shí)際使用中,用戶可能會(huì)對(duì)文件進(jìn)行不定時(shí)的更新,為了保證數(shù)據(jù)的實(shí)時(shí)性及在整個(gè)文件分享系統(tǒng)中的可靠性,就需要實(shí)現(xiàn)對(duì)特定文件夾的實(shí)時(shí)監(jiān)控。當(dāng)用戶對(duì)分享文件夾中的文件進(jìn)行操作時(shí),系統(tǒng)要及時(shí)更新系統(tǒng)數(shù)據(jù)庫(kù)中文件樹(shù),來(lái)保證數(shù)據(jù)完整性。在開(kāi)發(fā)中為了保證跨平臺(tái)及兼容性,通過(guò)封裝系統(tǒng)信號(hào)量監(jiān)控機(jī)制,來(lái)實(shí)現(xiàn)對(duì)不同平臺(tái)(包括Windows、Linux、Mac OS 等)的文件操作的實(shí)時(shí)監(jiān)控。
具體而言,使用Python 編程,通過(guò)對(duì)watchdog 模塊的擴(kuò)展來(lái)實(shí)現(xiàn),用來(lái)監(jiān)控指定目錄/文件的變化:
watchdog.events.FileCreatedEvent()
文件被創(chuàng)建時(shí)觸發(fā)該事件
watchdog.events.DirCreatedEvent()
目錄被創(chuàng)建時(shí)觸發(fā)該事件
watchdog.events.FileDeletedEvent()
文件被刪除時(shí)觸發(fā)該事件
watchdog.events.DirDeletedEvent()
目錄被刪除時(shí)觸發(fā)該事件
watchdog.events.FileModifiedEvent()
文件被修改時(shí)觸發(fā)該事件(修改文件內(nèi)容、修改文件inode 信息如權(quán)限和訪問(wèn)時(shí)間,都會(huì)觸發(fā)該事件)
watchdog.events.DirModifiedEvent()
目錄被修改時(shí)觸發(fā)該事件
通過(guò)對(duì)watchdog 事件處理類(lèi)的重構(gòu)及繼承,來(lái)實(shí)現(xiàn)針對(duì)文件共享目錄的實(shí)時(shí)監(jiān)控,每當(dāng)有文件操作發(fā)生在設(shè)定的共享目錄時(shí),系統(tǒng)就能根據(jù)具體的文件操作類(lèi)型,實(shí)時(shí)掃描文件修改,并通過(guò)FileTools 及Db-Tools 實(shí)時(shí)同步到服務(wù)器端數(shù)據(jù)庫(kù)中。
因?yàn)榭蛻舳艘鶕?jù)需求,使用HTTP 服務(wù)分享客戶端文件,又要降低對(duì)系統(tǒng)的負(fù)荷,減小對(duì)CPU 及磁盤(pán)I/O 影響,故使用Python 標(biāo)準(zhǔn)庫(kù)中自帶的http.server模塊,實(shí)現(xiàn)了一個(gè)小型、符合預(yù)期的HTTP 服務(wù)程序。
WEBDIR=path
PORT=config.http_prot
os.chdir(WEBDIR)
Handler=SimpleHTTPRequestHandler
with socketserver.TCPServer(('', PORT), Handler)as httpd:
print("serving at port",PORT)
httpd.serve_forever()
通過(guò)os.chdir()方法,將當(dāng)前路徑切換到設(shè)定的共享文件目錄上,來(lái)實(shí)現(xiàn)HTTP 服務(wù)的高效運(yùn)行。
通過(guò)創(chuàng)建Config 文件,將一些需要根據(jù)情境來(lái)更改的屬性綁定到一起,減少修改代碼的復(fù)雜性,當(dāng)用戶在自行部署時(shí),可以統(tǒng)一地在Config 文件中修改具體參數(shù),如數(shù)據(jù)庫(kù)賬號(hào)信息、開(kāi)放端口信息等,避免對(duì)代碼的文正行的修改和破壞[10]。
服務(wù)器端需要給用戶提供一個(gè)完善的UI 交互界面,滿足用戶的可視化操作要求,結(jié)合本系統(tǒng)的應(yīng)用需求,決定使用Web Server 形式提供給用戶類(lèi)似搜索引擎的文件查詢界面。針對(duì)本項(xiàng)目,建立了一個(gè)名為server 的Django App 應(yīng)用。
建立數(shù)據(jù)層
class files(models.Model):
time=models.CharField(max_length=100)
ip=models.CharField(max_length=100)
name=models.CharField(max_length=500)
filename=models.CharField(max_length=500)
class Meta:
db_table='ip_file_url'
來(lái)定義數(shù)據(jù)操縱的表結(jié)構(gòu),為后續(xù)數(shù)據(jù)操作實(shí)現(xiàn)類(lèi)定義。
定義兩個(gè)方法Headhtml(),Inquire()來(lái)完成系統(tǒng)操作。Headhtml()來(lái)完成用戶訪問(wèn)本系統(tǒng)時(shí),返回查詢首頁(yè)面的功能,當(dāng)用戶在窗口中輸入要查詢的文件名稱時(shí),通過(guò)post 方式提交到后臺(tái),而Inquire()方法用來(lái)接受用戶的查詢參數(shù),并使用models 中定義的數(shù)據(jù)表進(jìn)行對(duì)數(shù)據(jù)庫(kù)的查詢操作。
class MyFormView(View):
form_class=MyForm
template_name='result.html'
def post(self,request,*args,**kwargs):
form=self.form_class(request.POST)
if form.is_valid():
form=files.objects.filter(name_iexact=names)
return render(request, self.template_name, {'form':form})
當(dāng)在數(shù)據(jù)庫(kù)中查詢到具體條目時(shí),主動(dòng)渲染到result 模板中,并返回給用戶。
針對(duì)網(wǎng)絡(luò)安全問(wèn)題,尤其是在表單提交時(shí)的跨域攻擊問(wèn)題,特地在網(wǎng)頁(yè)模板中添加{%csrf_token%}標(biāo)簽,使用{%csrf_token%}生成一個(gè)input 框在form 表單中提交,每次post 請(qǐng)求提交有需要Django 生成的csrftoken 值,來(lái)防范跨域攻擊問(wèn)題。
在同一局域網(wǎng)中的多臺(tái)辦公電腦上進(jìn)行了系統(tǒng)測(cè)試,其中一臺(tái)電腦啟動(dòng)服務(wù)器端服務(wù)。圖2 和圖3 分別顯示在客戶端電腦進(jìn)行文件搜索及找到相關(guān)文件后的畫(huà)面,可以看到本文系統(tǒng)的實(shí)現(xiàn)效果如圖2。
圖2 文件搜索
圖3 文件下載
本文使用Python 語(yǔ)言編程,實(shí)現(xiàn)了整個(gè)分布式文件共享系統(tǒng)的功能,優(yōu)化設(shè)計(jì)的地方主要有:通過(guò)寫(xiě)入數(shù)據(jù)庫(kù)表的形式,實(shí)現(xiàn)對(duì)分享?xiàng)l目的動(dòng)態(tài)修改和對(duì)無(wú)效信息的及時(shí)清除,減少數(shù)據(jù)冗余,保證信息的準(zhǔn)確性。使用系統(tǒng)監(jiān)控機(jī)制,實(shí)現(xiàn)針對(duì)常見(jiàn)系統(tǒng)平臺(tái)的動(dòng)態(tài)監(jiān)控,使得該共享方式適用于各種系統(tǒng)平臺(tái)。用戶只需要運(yùn)行客戶端程序,隨時(shí)都可以加入到文件共享的隊(duì)伍中,其他的網(wǎng)絡(luò)用戶通過(guò)搜索,即可獲取相應(yīng)的文件。該方式實(shí)現(xiàn)簡(jiǎn)單有效,可滿足于各種辦公、教學(xué)環(huán)境使用,是一種可推廣的文件共享方式。
算法過(guò)程簡(jiǎn)潔明了,易于理解。系統(tǒng)實(shí)現(xiàn)部分給出了較直觀的圖,顯示了系統(tǒng)運(yùn)行時(shí)的共享文件搜索及文件下載界面。關(guān)于系統(tǒng)安全[11]及文件搜索過(guò)程中模糊查詢、內(nèi)容查詢等細(xì)化方面的工作,可作為下一步的研究方向。