P2P SDK開發(fā)包與無關(guān)性協(xié)議傳輸.doc_第1頁
P2P SDK開發(fā)包與無關(guān)性協(xié)議傳輸.doc_第2頁
P2P SDK開發(fā)包與無關(guān)性協(xié)議傳輸.doc_第3頁
P2P SDK開發(fā)包與無關(guān)性協(xié)議傳輸.doc_第4頁
P2P SDK開發(fā)包與無關(guān)性協(xié)議傳輸.doc_第5頁
已閱讀5頁,還剩62頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

P2P SDK開發(fā)包與無關(guān)性協(xié)議傳輸目錄:一綜述二PPQ.DLL是一個P2P SDK開發(fā)包三PPQ.DLL的特點四PPQ.DLL的工作方式五創(chuàng)建PBaseAct派生類六在開始一個任務(wù)之前的準(zhǔn)備工作七從URL下載一個文件八建立一個語音聊天九從另一個好友處下載一個文件十PPQ.DLL的無關(guān)性協(xié)義傳輸一綜述 PPQ.DLL通過對象和插件的封裝來實現(xiàn)無關(guān)性協(xié)義傳輸,允許開發(fā)者在不必知道傳輸協(xié)議的前提下,就可以進行插件的開發(fā),加快開發(fā)過程,減少錯誤的產(chǎn)生,提供了一種用TCP來實現(xiàn)事務(wù)處理的策略,在最后提出了一種比HTTP、XML和SOAP等更加靈活的包含執(zhí)行方法的,以傳送對象的方式實現(xiàn)的無關(guān)性協(xié)義傳輸。 二PPQ.DLL是一個P2P SDK開發(fā)包PPQ.DLL是一個P2P的SDK開發(fā)包,它使用對象的傳遞來實現(xiàn)無關(guān)性協(xié)議傳輸,這種對象并不是MFC或JAVA的序列化對象,PPQ.DLL的序列化對象,使開發(fā)者可以在互相不知道傳送協(xié)議的情況下,互傳消息,并且可以根據(jù)開發(fā)者的定義,在不同的編程語言環(huán)境中互傳對象。它將TCP的流式數(shù)據(jù)轉(zhuǎn)變成一個個事務(wù)來對待,每一個事務(wù)表明你希望通過P2P來實現(xiàn)的功能,事務(wù)的處理過程可以使用DLL、OCX或COM等任何一種形式封裝起來,這些被封裝的事務(wù)可以由其它開發(fā)者直接在自己的開發(fā)程序中引用,而不需要再為處理相同的事務(wù)去開發(fā)一套程序。 PPQ.DLL采用插件的形式來引用已定義好的事務(wù)處理程序,不但可以在開發(fā)程序時增加一個插件,而且允許程序在運行時動態(tài)增加或取消一個插件,使開發(fā)出來的程序,具備動態(tài)擴展功能,而不必每增加一個功能都重新發(fā)布一次程序,并且這種插件地增加和取消可以完全由用戶自己來決定。PPQ.DLL封裝了數(shù)據(jù)傳輸時的編碼方式,使開發(fā)者不用擔(dān)心開發(fā)程序與未來P2P國際標(biāo)準(zhǔn)之間的接軌,對于新的標(biāo)準(zhǔn)的適應(yīng),只需要簡單的修改一下底層的解碼器,所有原先的開發(fā)程序就可以自動地適應(yīng)新的國際標(biāo)準(zhǔn)。PPQ.DLL實際上提供了一種新的以對象方式實現(xiàn)的無關(guān)性協(xié)議傳輸,它類似于XML、HTTP、SOAP等協(xié)義,但有其獨特的特點,關(guān)于這種新的無關(guān)性協(xié)議傳輸?shù)目尚行詫⒃诤竺嬲撌觥?PPQ.DLL為P2P的應(yīng)用帶來了一個新的起點?,F(xiàn)在的P2P的應(yīng)用都是傳遞一種字符串來作為命令,它只能傳遞規(guī)則,而無法傳遞規(guī)則所表示的方法,并且這種規(guī)則到目前為止并沒有一個統(tǒng)一的標(biāo)準(zhǔn),如何建立標(biāo)準(zhǔn)與什么時候能夠建立標(biāo)準(zhǔn)都是一個期待的問題。在等待標(biāo)準(zhǔn)公布時,每一家大的公司都在努力制定自己的協(xié)義與標(biāo)準(zhǔn),都希望將來的標(biāo)準(zhǔn)能夠與自己的相同,在標(biāo)準(zhǔn)公布以后,所有的與標(biāo)準(zhǔn)不同的程序,如果想適應(yīng)標(biāo)準(zhǔn),都必需去修改原程序,這個改動是很龐大的,而PPQ.DLL正是解決了這個問題。PPQ.DLL的傳輸沒有任何的協(xié)議,任何一個開發(fā)者都可以制定自己的協(xié)議標(biāo)準(zhǔn)去完成一個任務(wù),而不需要去關(guān)心其它的應(yīng)用程序。對于想通過P2P來實現(xiàn)的功能,只需要加入一個已經(jīng)定義好的類就可以啦,如果想在其它開發(fā)者開發(fā)的事務(wù)處理程序基礎(chǔ)之上去增加一些功能,甚至可以從其他開發(fā)者已經(jīng)定義好的類中派生出新的本地類來實現(xiàn)自己的獨特功能,而發(fā)送指令對象的雙方卻都可以正確地解析,并且可以在雙方的處理過程中,都引入自己獨特的本地處理方式。PPQ.DLL是一種真正地?zé)o協(xié)義傳輸方式,它的引入可以使P2P在一些關(guān)鍵性領(lǐng)域中得到真正地應(yīng)用,它的這種插件式自由組合方式,也使程序地開發(fā)得到了最大化的復(fù)用,能夠更好地加快程序開發(fā)速度,使每一次的開發(fā)都不必再從起跑線上開始。利用PPQ.DLL的對象傳遞方式,PPQ.DLL將P2P實現(xiàn)的基本功能都封裝在了DLL中,開發(fā)者可以直接把它作為一個開發(fā)包來使用,其他開發(fā)者利用PPQ.DLL的對象傳遞方式開發(fā)出的插件,也可以直接無縫地加入開發(fā)包中,使開發(fā)P2P產(chǎn)品變得輕松自如。PPQ.DLL也提出了防止目前P2P上盜版、黃色信息、無用的垃圾信息大量泛濫的一種方法,讓P2P的使用更加規(guī)范,使個人用戶的行為更加具有針對性和目的性。從開發(fā)JAVA版的P2P程序開始,我就始終認(rèn)為P2P應(yīng)該對下載的文件設(shè)定一種權(quán)限,用戶通過權(quán)限可以控制自己所提供的文件可以被哪一些人下載,這種想法也影響到了我開發(fā)C+版的PPQ.DLL。國內(nèi)目前開發(fā)的P2P程序中對下載文件都沒有任何的限制,其直接導(dǎo)制的后果就是大量的黃色信息呈輔射狀傳播,一個下載了黃色信息的用戶無形之中成為了一個傳播黃色信息的新的源,形成了非常壞的一個惡性循環(huán),最終導(dǎo)制目前國內(nèi)所有P2P網(wǎng)站全部暫停。PPQ.DLL對用戶的所有傳送文件采用數(shù)字標(biāo)識來傳遞,這種數(shù)字標(biāo)識可以和一些描述性的詞匯一起被傳送給其它用戶,用戶想下載時,也是傳遞數(shù)字標(biāo)識,而并不是直接傳遞想下載的文件名,傳送方在接收到數(shù)字標(biāo)識后通過程序去查找到該數(shù)字標(biāo)識所對應(yīng)的正確的本地文件名,在這個過程中,傳送方可以檢驗請求傳送的用戶是否有權(quán)限下載該文件,如果有,則開始傳遞文件,否則會駁回該用戶的請求。數(shù)字標(biāo)識的引入為安全性和擴展性帶來了很多的好處:1用戶不必再設(shè)定某一個共享目錄,文件可以散布在本地機器的任何一個目錄下,而不用擔(dān)心安全性。2避免了垃圾文件的出現(xiàn),設(shè)定共享目錄時,用戶常常將一大堆文件拷貝到目錄下,結(jié)果檢索出來的經(jīng)常是一大堆垃圾。3可以為任何一個文件加入權(quán)限設(shè)定,使用戶可以靈活得控制每一個文件的一個或一組下載方。4每一下載方只能看到自己可以下載的內(nèi)容,不在權(quán)限內(nèi)的下載內(nèi)容根本就看不到。5為將來的應(yīng)用增加了可擴展性,從數(shù)字標(biāo)識到正確的本地文件的轉(zhuǎn)換過程,提供了一種方便地擴展手段,以什么方式來設(shè)定權(quán)限、如何校驗權(quán)限、是否使用權(quán)限、以及對不同文件采取不同加密手段等都可以在這個轉(zhuǎn)換過程中根據(jù)具體情況來定義。 通過以上方法,只能防止文件的泛濫傳播,還不能有效地控制黃色信息。從用戶端來控制黃色信息是很困難的,因為寫的任何一個過濾代碼都很容易就會被破解,從而根本起不到過濾黃色信息的目的,所以最終還是應(yīng)該從服務(wù)器來控制。PPQ.DLL的想法是將用戶提供的公共信息源采用分布式數(shù)據(jù)庫的方式保存,由專門的服務(wù)器提供一個強大的搜索引擎,用戶通過這個搜索引擎來檢索公共信息,在這個搜索引擎中設(shè)置過濾器,濾除黃色信息,這是避免黃色信息泛濫傳播的一個有效方法。(用戶在幾個人的小范圍內(nèi)進行的傳播,應(yīng)該不在考慮范圍之內(nèi),而且也根本就不可能完全地控制住。)PPQ.DLL在服務(wù)器開發(fā)方面,提出了一種“全球服務(wù)器統(tǒng)一資源分配”策略,這種方式,對服務(wù)器的負(fù)擔(dān)非常輕,可以由任意多個服務(wù)器提供商去獨立地創(chuàng)建自己的用戶群,建立自己的用戶檔案庫,彼此間不需要頻繁交換信息,也不需要彼此共享用戶資源,更用不著建立中心數(shù)據(jù)庫,但是在任何一臺服務(wù)器上登錄的用戶彼此間卻可以互相通訊,可以不通過服務(wù)器而建立連接。 三PPQ.DLL的特點1在P2P標(biāo)準(zhǔn)尚未統(tǒng)一的情況下,開發(fā)者都在獨立的制定自己的傳送協(xié)議,使開發(fā)出來的程序彼此無法互相通訊,而且采用不同編程語言開發(fā)出的產(chǎn)品,在互相通信時也會存在問題,PPQ.DLL正是為解決這個問題而開發(fā)的。PPQ.DLL是建立在任何一種標(biāo)準(zhǔn)協(xié)議之上的一種公共接口,它不但能簡化開發(fā)過程,而且標(biāo)準(zhǔn)化了傳送和接收的過程,使開發(fā)者可以在各自制定協(xié)議的前提下,仍然能夠?qū)崿F(xiàn)互相通訊,并且可以在采用不同的編程語言開發(fā)的產(chǎn)品之間互相傳遞指令對象。2PPQ.DLL封裝了采用TCP進行文件傳送與接收的全過程。只需要給出連接方的IP地址、監(jiān)聽端口號和想傳送(或下載)的文件的數(shù)字標(biāo)識號,PPQ.DLL會自動地以多線程、斷點續(xù)傳的方式實現(xiàn)文件的傳送與接收過程。3PPQ.DLL封裝了以HTTP方式從URL地址下載文件的全過程。只需要給出想下載的URL地址,PPQ.DLL會自動地根據(jù)服務(wù)器端是否支持?jǐn)帱c續(xù)傳,來決定采用單線程還是多線程方式下載。支持重定向。4PPQ.DLL封裝了以TCP方式進行語音聊天的全過程,只需簡單地調(diào)用幾個靜態(tài)函數(shù),就可以輕易地啟動、暫停、關(guān)閉聲音捕捉(錄音)和聲音回放(放音),并初步實現(xiàn)了靜音過濾。5PPQ.DLL封裝了進行數(shù)據(jù)傳輸?shù)木幋a方式和傳送的具體過程,將數(shù)據(jù)的傳送和接收轉(zhuǎn)變成對象的傳送和接收,使處理過程標(biāo)準(zhǔn)化。使用PPQ.DLL來開發(fā)程序,不用直接和字符串打交道,不必再去解析從SOCKET接收到的字符串編碼,開發(fā)者可以將想傳送的信息定義成指令對象的屬性,直接發(fā)送指令對象,PPQ.DLL會自動將指令對象轉(zhuǎn)變成數(shù)據(jù)流發(fā)出。SOCKET所接收到的數(shù)據(jù),PPQ.DLL會自動轉(zhuǎn)變成對應(yīng)的指令對象,以WINDOWS消息或回調(diào)函數(shù)的方式通知接收方,使整個的開發(fā)過程變得更加簡單和模塊化。6PPQ.DLL的對象數(shù)據(jù)流處理并不是MFC的序列化對象,它比MFC的序列化對象更加簡單、易用,允許在修改對象屬性后,重復(fù)發(fā)送對象,而且能夠在無法實別所傳送的類對象時,自動還原成與該類最接近的一個基類的對象。PPQ.DLL的序列化解碼過程采用純C+編寫,可以很容易地改寫成其它的語言。7PPQ.DLL的對象流的實現(xiàn)過程和方法被完全地封裝在了DLL中,對于實現(xiàn)對象流的算法的優(yōu)化,甚至是改變對象流的傳送格式,都不會對使用PPQ.DLL的開發(fā)者造成任何影響,使開發(fā)者可以完全放心地開發(fā)程序,而不用擔(dān)心標(biāo)準(zhǔn)與協(xié)議的改變。經(jīng)過數(shù)次的改寫和優(yōu)化,正式版的PPQ.DLL不但可以傳送任意大小的指令對象,并且在接收指令對象時,從SOCKET中讀出的數(shù)據(jù)將直接被寫到指令對象相應(yīng)的屬性的緩沖區(qū)中,中間不再需要經(jīng)過任何一次緩沖區(qū)的復(fù)制過程,大大地加快了速度。8如果你認(rèn)為使用PPQ.DLL開發(fā)的不同產(chǎn)品,只不過是界面上的不同,那你就錯啦。PPQ.DLL提供了豐富的接口和靈活的開發(fā)方式,使你完全可以開發(fā)出具有鮮明特點和獨立功能的程序。PPQ.DLL只是封裝了連接實現(xiàn)的過程和握手協(xié)議,對建立連接后,雙方傳送的信息并沒有作出任何規(guī)定和假設(shè),它只是提供了一種公共的接口。9開發(fā)者可以根據(jù)自己的需要去創(chuàng)建新的類,來表明一種類型的指令,這種類型的指令完成一種特定的功能,開發(fā)者可以將自己創(chuàng)建的指令和指令的解析程序一起打包成一個DLL,發(fā)布出來,同時公布該類的ClassID。其它的開發(fā)者可以在自己的程序中直接引用這個DLL,來完成由其它開發(fā)者預(yù)先定義好的功能。PPQ.DLL內(nèi)部也定義了一些派生類,這些派生類都是完成一種特定功能的指令對象。10PPQ.DLL提供了一個鉤子函數(shù),用來返回開發(fā)者自定義的類的對象。如果你的自定義類是你發(fā)布的DLL中的一個內(nèi)部類,即自定義的類被完全地封裝在了你提供的DLL中,那么這個類的類名可以是任意的,不用擔(dān)心會重名。當(dāng)其他開發(fā)者要使用你的DLL時,只需要增加你提供的鉤子函數(shù)即可。但是類的ClassID還是需要公布的,以避免與其他開發(fā)者的ClassID重復(fù)。握手協(xié)議的傳遞和語音聊天的傳送與接收采用的就是指令對象的方式來進行傳送,這些對象都被封裝在了PPQ.DLL內(nèi)部,開發(fā)者只需要通過接口來啟動一個或一組功能,而不需要直接去同這些對象打交道。因為這些類被完全地封裝在了PPQ.DLL內(nèi)部,因此,即使你在開發(fā)過程中定義了一個與這些對象重名的類,也不會對程序造成任何的影響。 四 PPQ.DLL的工作方式PPQ.DLL通過消息與回調(diào)函數(shù)和DLL外部進行交互,要想正確地使用這個DLL,就需要了解PPQ.DLL中對外發(fā)布的幾個類。PPQ.DLL中一共對外提供了5個類:PDefine、PFriend、PBaseAct、PTask和CStringEx。 PDefine類中定義了開發(fā)者需要使用的結(jié)構(gòu)、回調(diào)函數(shù)、常量以及PPQ.DLL定義的一些消息和靜態(tài)方法。這個類不需要去創(chuàng)建實例,它里面的所有方法和屬性都是靜態(tài)的。這些定義對正確地了解和撐握PPQ.DLL是非常關(guān)鍵的。 PPQ的整個連接過程是建立在一種信任的基礎(chǔ)之上的。即如果A信任B,B也信任A,那么A與B之間可以互相連接,否則連接不能被建立。這種信任的關(guān)系不能夠被繼承,即如果A信任B,B信任A、C,C信任B,這并不表示A也信任C,A可以和B之間互連,B即可以和A,也可以和C之間互連,但A不可以和C這間互連。即信任只能是雙方的事情。這種信任關(guān)系的表現(xiàn)的實體,就是PFriend類。PFriend類中定義了被連接方的身份標(biāo)識(ID)、IP地址、監(jiān)聽端口號等相關(guān)信息,是對被連接方的一個描述(連接與被連接都是從自己這一方來看的)。通常開發(fā)者需要從該類中派生出新的類,以記錄關(guān)于被連接方的更多的詳細(xì)資料。在PPQ.DLL中,被連接的一方都稱為好友,每一個好友都必需有一個PFriend對象與之對應(yīng),除了進行HTTP連接時不需要用到PFriend對象,其它進行的所有連接都是針對于某一個PFriend對象而進行的。希望互相連接的雙方,彼此都必需包括有對方的PFriend對象,否則連接是無法被建立的。 PPQ.DLL認(rèn)為要傳輸?shù)臄?shù)據(jù)應(yīng)該被分為2種,一種是指令,表示完成某一種功能,另一種是數(shù)據(jù),它的實際意義由以前傳遞的指令來表明。指令和數(shù)據(jù)往往是相關(guān)連的,失去任何一方,都會失去其表示的有效意義,因此,這2種實際應(yīng)該是一個整體,而這個整體在PPQ.DLL中表現(xiàn)出的實體,就是PBaseAct類。指令和數(shù)據(jù)被封裝在一個PBaseAct類中,作為一個整體來傳輸,這就是指令對象。PBaseAct是所有可以轉(zhuǎn)變?yōu)閿?shù)據(jù)流進行傳輸?shù)闹噶顚ο蟮幕?,開發(fā)者需要自定義傳輸對象時,都需要從該類來派生出新的類。只有該派生類的實例才可以直接作為一個對象從SOCKET中進行傳送與接收。 建立連接應(yīng)該是有目的性的,即建立連接應(yīng)該是為了具體完成某一項工作,建立多個連接的目的是為了更好、更快地協(xié)同完成這項工作。在PPQ.DLL里,某一項工作用任務(wù)來表示,而任務(wù)的表現(xiàn)實體,就是PTask類。PTask類描述并記錄了一個或一組具有相同連接類型的連接,它表明了要進行的一個任務(wù)。 CStringEx類是針對于MFC的CString類的一個擴展,它的主要作用是傳遞大數(shù)據(jù)量的二進制流緩沖,通過操作符重載,CStringEx類可以使用+=符號,直接追加一個字符串或一個int類型的數(shù)字。通過方法,還可以追加一個中間包含0終結(jié)符的二進制的流緩沖。你可以使用CStringEx類在任何一個需要動態(tài)改變緩沖區(qū)大小的地方,代替原來的數(shù)據(jù)緩沖區(qū),包括字符緩沖區(qū)、音頻緩沖區(qū)、視頻緩沖區(qū)等接收緩沖區(qū),使用CStringEx就和使用一個char*是一樣的,在使用過程中,你可以直接得到CStringEx的數(shù)據(jù)緩沖區(qū),將它轉(zhuǎn)換成任意類型的緩沖區(qū)來使用。CStringEx對象用來保存指令對象中需要傳送的大型數(shù)據(jù),在構(gòu)成指令對象時,如果指令對象需要發(fā)送比較長的數(shù)據(jù)(建議超過1K)時,都應(yīng)使用CStringEx來保存,因為在傳送指令對象時,對CStringEx對象作了優(yōu)化處理,它的傳送速度會比傳送CString類型的對象要快得多。 五 創(chuàng)建PBaseAct派生類PPQ.DLL沒有對外提供任何的指令對象,因此,使用DLL的第一件事情,就是創(chuàng)建自己的PBaseAct派生類。創(chuàng)建PBaseAct派生類其實很簡單,按照以下步驟,你就可以輕松地創(chuàng)建出自己的派生類。1在派生類的.h文件中加入SELF_SERIALIZE()序列化宏。SELF_SERIALIZE()宏需要傳遞2個參數(shù),第一個參數(shù)是當(dāng)前派生類的類名,第二個參數(shù)是該派生類的直接基類的類名。即如果你的派生類名為PLoginAct,它由PChatAct類派生,則宏調(diào)用為SELF_SERIALIZE(PLoginAct,PChatAct);2在派生類中重載CountSerializeLength()方法。3在派生類中重載UniteValue()方法。4在派生類中重載InitObject()方法。5在派生類中重載GetClassID()方法,返回自定義類的ClassID。6實現(xiàn)GOCALLBACK鉤子函數(shù),返回自定義對象的一個實例。 關(guān)于GOCALLBACK鉤子函數(shù)的定義和實現(xiàn)方法,請查閱PDefine.h文件中的回調(diào)函數(shù)說明。7實現(xiàn)GETCALLBACK回調(diào)函數(shù),對自定義對象進行處理。 或者定義一個PMSGINFO結(jié)構(gòu),通過消息來處理自定義對象。 關(guān)于GETCALLBACK回調(diào)函數(shù)和PMSGINFO結(jié)構(gòu)的定義和實現(xiàn)方法,請查閱PDefine.h文件中的回調(diào)函數(shù)說明和結(jié)構(gòu)說明。8如果在第7步中定義了一個PMSGINFO結(jié)構(gòu),則在派生類中重載基類PBaseAct中的virtual LPPMSGINFOGetCallBackMsg()方法,返回指向PMSGINFO結(jié)構(gòu)的指針。如果在第7步中實現(xiàn)了GETCALLBACK回調(diào)函數(shù),則在派生類中重載基類PBaseact中的virtual GETCALLBACK* GetParseActFunPointer()方法,返回指向GETCALLBACK回調(diào)函 數(shù)的指針。這兩個函數(shù)你只需要重載一個,建議重載GETCallBackMsg()方法,通過消息來處理指令對象。如果兩個函數(shù)都重載了,將優(yōu)先處理回調(diào)函數(shù)。9調(diào)用PDefine:SetUserGetObjectFunHook(),將在第6步中實現(xiàn)的GOCALLBACK鉤子函數(shù)的地址作為參數(shù)傳遞。六 在開始一個任務(wù)之前的準(zhǔn)備工作PPQ.DLL會向DLL的外部傳遞一些很重要的消息,這些消息必需被響應(yīng),否則PPQ.DLL無法正常正作。另外,還有一些是必需賦值的靜態(tài)屬性,被定義在了PDefine類中。1 初始化PDefine:rSMsgInfo結(jié)構(gòu)。2 實現(xiàn)回調(diào)函數(shù)GETPALCALLBACK,并將回調(diào)函數(shù)的地址賦給PDefine:pSGetFriendCallBackFun屬性。3 實現(xiàn)回調(diào)函數(shù)GETFILENCALLBACK,并將調(diào)函數(shù)的地址賦給PDefine:pSGetFileNCallBackFun屬性。4 為PDefine:szSelfFriendID屬性賦初值,表明自己的ID。5 為以下消息創(chuàng)建響應(yīng)函數(shù):OMSG_CREATE_NEW_OBJ,OMSG_CREATE_NEW_TASK,OMSG_ALL_CONNECT_END,OMSG_MISSION_END6 調(diào)用PDefine:SInitSocketStream()方法初始化Win Socket,使創(chuàng)建SOCKET連接成為可能。7 調(diào)用PDefine:SCreateTCPListenPort()方法創(chuàng)建TCP監(jiān)聽端口。8 調(diào)用PDefine:SSetUserGetObjectFunHook()方法設(shè)定鉤子函數(shù)。9 為想建立連接的對方,建立PFriend對象,并填寫上他ID、IP地址和TCP監(jiān)聽端口號。 七 從URL下載一個文件最簡單的任務(wù)就是從URL下載一個文件。PPQ.DLL封裝了通過HTTP下載的全過程,你想在自己的軟件中增加網(wǎng)絡(luò)螞蟻和FlashGet的功能嗎?不要著急,使用PPQ.DLL,你只需要調(diào)用幾個函數(shù),就可以實現(xiàn)自動下載的過程。1 在堆中創(chuàng)建一個PRECVINFO結(jié)構(gòu)。LPPRECVINFO lprInfo=new PRECVINFO();2 初始化結(jié)構(gòu),這步是必需的,每創(chuàng)建一個PRECVINFO結(jié)構(gòu),就應(yīng)該調(diào)用以下的方法初始化結(jié)構(gòu)。memset(lprInfo,0,DWORD(&lprInfo-nPort)-(DWORD)lprInfo);3 設(shè)定URL地址。lprInfo-strSrvURL =/ptmini.exe;4 設(shè)定下載后文件被保存的路徑,如果缺省,文件將被保存在當(dāng)前目錄下。lprInfo-strSaveBasePath=d:;5 創(chuàng)建一個PTask對象,準(zhǔn)備開始一個新的任務(wù)。PTask* pTask=new PTask();6 設(shè)定啟動多少個線程同時下載。pTask-SetMaxThreadNo(10);7 將PRECVINFO結(jié)構(gòu)的地址賦給PTask對象。pTask-m_lprRecvInfo=lprInfo;8 開始執(zhí)行一個HTTP下載任務(wù)。pTask-StartTask(TASK_HTTP_RECV);任務(wù)在執(zhí)行過程中會向PDefine:rSMsgInfo結(jié)構(gòu)中定義的窗體發(fā)送消息,以表明當(dāng)前的任務(wù)執(zhí)行狀態(tài)。任務(wù)結(jié)束后,窗體也會接收到消息以表明當(dāng)前任務(wù)是否已經(jīng)完成。關(guān)于這些消息的說明,請查閱PDefine.h中的消息的說明。 八 建立一個語音聊天想實現(xiàn)自己的IPPhone嗎?想和你在國外的朋友互訴一下衷腸嗎?不用再擔(dān)心昂貴的國際長途費用,寫個小的程序,一切就OK啦。你會發(fā)現(xiàn),使用PPQ.DLL實現(xiàn)一個語音聊天非常簡單。1 開始一個聊天任務(wù),其中this-m_pFriend是一個已經(jīng)創(chuàng)建好的PFriend對象。PTask* pTask=new PTask();pTask-m_pFriend=this-m_pFriend;pTask-StartTask(TASK_TCP_CHAT);2 啟動聲音播放設(shè)備PDefine:SPlaySound();3 初始化聲音捕捉設(shè)備PDefine:SGetSoundCaptureDeviceList(NULL);PDefine:SInitSoundCaptureDevice(NULL);PDefine:SGetSoundCaptureAvailableFormats(NULL);PDefine:SCreateSoundCaptureBuffer(NULL);4 設(shè)置捕捉到的聲音被傳遞給哪一個好友。PDefine:SSetSoundCaptureAcceptdFriend(this-m_pFriend);5 開始聲音捕捉。PDefine:SRecordSound();經(jīng)過以上的步驟,一個語音聊天已經(jīng)被創(chuàng)建了,并且自動地開始捕捉聲音,一旦有一個有效的聲音被捕捉到,就會立即被傳給指定的好友,接收到的聲音被按照接收時的順序排在一個隊列中,聲音播放設(shè)備會自動按照順序播放。實際上,你已經(jīng)可以同時和多人進行聊天,每個人都可以同時和你說話,但是在任意一個時刻你只能對其中一個人講話。在集成IP組播以后,會提供方法,以實現(xiàn)同時將聲音傳遞給多個好友。PPQ.DLL在語音的傳輸?shù)膶崿F(xiàn)上和其它程序?qū)崿F(xiàn)語音傳輸?shù)姆绞接泻艽蟮牟煌?。大部分程序在實現(xiàn)語音傳輸時通常是啟用2個TCP連接來完成(UDP方式除外),一個TCP連接用來傳輸控制命令或消息,一個TCP連接用來專門傳輸聲音數(shù)據(jù),因為它們的聲音數(shù)據(jù)必需是連續(xù)傳輸?shù)?,即一旦啟動語音聊天,即使你沒有說話,也會有連續(xù)不斷地數(shù)據(jù)被傳送到連接方。PPQ.DLL通過一個簡單的語音過濾功能,不再傳送靜音的數(shù)據(jù),以減少不必要的數(shù)據(jù)傳遞量。另外,PPQ.DLL采用的是對象的傳遞方式,它只通過一個TCP連接來實現(xiàn)聊天,不管是文字聊天還是語音聊天,采用的都是同一個連接,你可以在聊天的過程中,一邊進行語音聊天,一邊通過聊天連接傳送其它的數(shù)據(jù),而彼此之間并不會互相干擾。 九 從另一個好友處下載一個文件通過在2個客戶端之間建立一個連接,來完成指定文件的傳送與接收,是P2P的基本功能。PPQ.DLL封裝了整個過程,采用了多線程,斷點續(xù)傳的方式來實現(xiàn)文件的傳送與接收,使處理標(biāo)準(zhǔn)和簡單化。1 初始化開始一個傳送或接收任務(wù)所必需的步驟LPPRECVINFO lprInfo=new PRECVINFO();memset(lprInfo,0,DWORD(&lprInfo-nPort)-(DWORD)lprInfo);lprInfo-strSaveBasePath=d:;PTask* pTask=new PTask();pTask-SetMaxThreadNo(5);pTask-m_lprRecvInfo=lprInfo;2 設(shè)定連接到哪一個好友,其中this-m_pFriend是一個已經(jīng)創(chuàng)建好的PFriend對象。pTask-m_pFriend=this-m_pFriend;3 設(shè)定想下載的文件的數(shù)字標(biāo)識pTask-m_dwFileID=100;4 開始一個通過TCP來接收文件的任務(wù)。pTask-StartTask(TASK_TCP_RECV);與好友之間的連接被自動地建立,并啟動多線程來完成文件的接收。PPQ.DLL只有在連接被確定建立后,才會啟動一個新的線程來接收數(shù)據(jù),并不向FlashGet那樣,只要有一個連接被建立,就會啟動最大的線程個數(shù),去償試連接,結(jié)果經(jīng)常是多個連接無法被建立,而線程卻都被啟動了,每個線程都在努力地償試連接。PPQ.DLL在采用TCP和HTTP方式下載時,都遵循著這樣一個原則:先償試連接,等到連接被建立后才啟動新的線程,等到開始傳送有效數(shù)據(jù)后,才會去償試進行下一個連接,以避免很多無效的線程被啟動。 十PPQ.DLL的無關(guān)性協(xié)義傳輸PPQ.DLL的對象傳送并不是MFC和JAVA的序列化對象,它使用了一套比MFC和JAVA更為先進的序列化對象的方式,在解碼時不但可以正確地將傳送時的對象還原出來,而且可以在傳送的類無法識別的情況下,自動地還原成與傳送的類最接近的一個基類的對象。PPQ.DLL的解碼和編碼程序,采用純C+編寫,可以很容易地改寫成其它語言,整個解碼和編碼過程不需要任何的語法分析,也不用對數(shù)據(jù)進行掃描,所有編碼和解碼過程采用順序執(zhí)行過程,執(zhí)行速度非常快,而且整個的編碼和解碼程序編譯后只有幾K大小。 在開發(fā)PPQ.DLL的初期,只是為了將P2P的具體連接過程和傳輸數(shù)據(jù)的過程封裝起來,以簡化P2P的開發(fā),并且使彼此開發(fā)的程序,可以在自定義傳輸協(xié)議的情況下互相通信,它的基本思路是采用對象作為基本信息單位來傳遞。TCP采用的是一種流式的數(shù)據(jù)傳送方式,因此對于接收方來講,在接收有效數(shù)據(jù)之前,必需明確地接收一些數(shù)據(jù),來表明其后的有效數(shù)據(jù)所表示的意義,這里暫且把表明其后有效數(shù)據(jù)意義的數(shù)據(jù),稱作指令,把指令后所傳送的有效數(shù)據(jù)稱為值,可以看出,實際的流式數(shù)據(jù)是由指令和值來構(gòu)成的。指令和值一起才能夠明確地表示出數(shù)據(jù)的有效意義,沒有指令的數(shù)據(jù),實際是無效的,因為無法明確地知道它所表示的意義。指令和值可以重復(fù)出現(xiàn)多次,并且值由字節(jié)構(gòu)成,每個字節(jié)由8位二進制來表式,其長度可以是任意的,沒有限制。一個或一組指令和值組合在一起,就構(gòu)成了指令對象。重復(fù)出現(xiàn)的一個或一組指令對象可以明確地表明希望接收方去完成某一種操作,這些指令對象和要完成的操作一起構(gòu)成了一個事務(wù),所以TCP的應(yīng)用實際是一種基于事務(wù)的處理。 MFC和JAVA都提供了非常完善的序列化對象方式,但可惜的是,彼此之間無法互用,MFC的對象只能由MFC來解析,JAVA也是一樣,因此,要想實現(xiàn)跨平臺操作,就不能使用它們的序列化對象方式。SOAP和XML也是一種很好地與平臺無關(guān)的傳輸協(xié)義,來標(biāo)準(zhǔn)化數(shù)據(jù)傳送時的格式,但它們都是對字符串來進行操作,這也并不符合TCP傳輸二進制流的概念。 如果將傳送數(shù)據(jù)作為字符串來表示,就不得不考慮不同平臺的字符編碼問題,但是這種考慮與實際的數(shù)據(jù)傳送是相違背的,因為傳送的數(shù)據(jù)實際都是以二進制字節(jié)來傳送的。為了將傳送數(shù)據(jù)以二進制字節(jié)方式來傳送,PPQ.DLL重新定義了一套序列化對象的方式,在序列化對象時,將對象轉(zhuǎn)變成二進制流來傳送,在反序列化時,直接將二進制流拷貝到對象相應(yīng)的屬性的緩沖區(qū)中,而不再以字符串的形式來出現(xiàn),避開了不同平臺對字符編碼的問題。PPQ.DLL的序列化和反序列化對象時,無需定義任何的語法規(guī)則,也沒有定義任何的不可用字符,所有的數(shù)據(jù)均是以字節(jié)為單位來傳送和接收,在反序列化對象時,不需要對接收數(shù)據(jù)進行任何的掃描,也沒有使用循環(huán),所有操作均是順序完成,指令形成速度非常快,并且可以自動探測并丟棄未知指令對象和錯誤的指令對象,即使接收數(shù)據(jù)中間出現(xiàn)錯誤,仍然能夠跳過錯誤的數(shù)據(jù),正確地接收后續(xù)的指令對象。將TCP的流式數(shù)據(jù)作為事務(wù)來處理的最大好處是,可以用一個DLL、OCX或COM等組件來封裝一個或多個事務(wù)的具體處理過程,所有的事務(wù)處理都是基于指令對象來進行的處理,而不用去追究數(shù)據(jù)的來源。封裝后的事務(wù)可以直接被其他的開發(fā)者調(diào)用,而不需要再為處理相同的事務(wù)去重復(fù)開發(fā)程序,能更好地加快開發(fā)過程,減少錯誤發(fā)生的機率。這是PPQ.DLL的一個宗旨。 PPQ.DLL本身并沒有規(guī)定連接雙方應(yīng)該傳送的指令對象,它采用插件的形式,支持外部掛接任意多組指令對象,交由PPQ.DLL處理的數(shù)據(jù)會被PPQ.DLL自動解析成指令對象,但是哪一些指令對象是開發(fā)者需要的,卻是由開發(fā)者自己來定義的。只有開發(fā)者規(guī)定的指令對象,PPQ.DLL才會將指令對象提交給相應(yīng)的指令對象的處理程序,對于不可識別的指令對象,PPQ.DLL會自動地丟棄。PPQ.DLL的序列化對象與MFC和JAVA的序列化對象的最大不同點在于,MFC和JAVA的序列化對象只能將對象還原成原來保存的類的對象,即如果原來保存的類不存在,則反序列化時會失敗,并拋出異常。PPQ.DLL的序列化對象在反序列化過程中,會自動分析數(shù)據(jù)流所表示的類是否可以識別,如果不能識別,則會查找該類的基類,找到一個與數(shù)據(jù)流所表示的類最為接近的一個基類,然后還原成該基類的一個對象,調(diào)用該基類對象的指令處理程序處理該指令,派生類中的多余的不可識別的數(shù)據(jù)會被自動丟棄。 PPQ.DLL的反序列化方式是進行無關(guān)性協(xié)義傳輸?shù)囊粋€關(guān)鍵。 讓我們分析一下互聯(lián)機器進行數(shù)據(jù)通訊的過程。以HTTP信息頭為例,在HTTP協(xié)議中規(guī)定HTTP的頭可以包含任意多行信息,每一行之間用rn結(jié)束,連續(xù)的2個rn表示整個HTTP信息頭結(jié)束,其后緊接著為有效數(shù)據(jù)。在HTTP的信息頭中,有一部分是每一個HTTP信息頭都必需包含的信息,如HTTP標(biāo)志,版本號,返回代碼等,這個公共部分實際上就是一個基準(zhǔn)的類。HTTP信息頭對于不同的服務(wù)器來講,它是允許擴充的,可以加入一些對于該服務(wù)器能夠解析的其它標(biāo)志,來指示服務(wù)器采取一些特定動作,這實際是對原基準(zhǔn)類的一個擴充,相當(dāng)于原基準(zhǔn)類的一個派生類。一個用戶傳遞了一個派生類對象,服務(wù)器在接收到派生類對象時,如果它能夠識別這個派生類,表示它需要根據(jù)這個派生類來執(zhí)行一些特定的操作,則在反序列化時,會創(chuàng)建出這個派生類的對象,通知服務(wù)器。如果服務(wù)器不識別這個派生類對象,在反序列化時,會自動地查找該服務(wù)器可以識別的該類的一個最接近的基類,這個基類中所保存的數(shù)據(jù)將是這個服務(wù)器所關(guān)心的數(shù)據(jù),DLL會創(chuàng)建出這個基類,然后通知服務(wù)器。 PPQ.DLL的優(yōu)勢在什么地方呢?HTTP和XML等協(xié)議,其傳遞的都是字符串,接收方需要去解析字符串,找到自己感興趣的標(biāo)識,再次分解字符串,得到指定的值。每一個接收方都必需去實現(xiàn)這個過程,當(dāng)然我們可以使用XML語法解析器將XML造型成對象來處理。讓我們關(guān)注一下XML造型成對象的過程,就會明顯地感受到它與PPQ.DLL的反序列化對象的本質(zhì)區(qū)別。HTTP和XML必需同時傳遞屬性名稱和屬性的值,因為接收方在解析對象時,實際并不知道原來傳遞的內(nèi)容是什么,它只是將屬性名稱和值保存在哈希表中,屬性名相當(dāng)于哈希表的一個鍵,而屬性的值相當(dāng)哈希表中該鍵的值。當(dāng)接收方訪問屬性時,實際是在哈希表中搜索指定的鍵,然后返回給用戶該鍵所表示的值。從這里面,我們可以看出這樣一個問題,接收方必需知道鍵的正確含義,否則它無法得到該鍵所表示的值。即然接收方已經(jīng)知道了鍵,那么為什么還需要去傳遞這個鍵呢?答案很簡單,如果不傳遞鍵,它無法區(qū)分值應(yīng)該對應(yīng)到哪一個鍵。我們再看一下PPQ.DLL是如何反序列化對象的。即然鍵對于接收方來講是已知的,它當(dāng)然可以作為對象中的一個屬性來存在,這和XML解析器將XML轉(zhuǎn)變成XML對象是一個道理。每一個XML的語法都可以作為一個指令類或一個指令類的派生類,而XML的屬性相當(dāng)于類中的一個屬性,使用PPQ.DLL可以直接傳遞這個指令對象,PPQ.DLL序列化時并沒有傳遞屬性的名稱,它只把類作為一個整體來傳遞,而類對象的解析過程是由類自己來定義的,因此,它仍然能夠被完整地解析出來。通過PPQ.DLL反序列化出來的類對象是傳送方傳遞的類或基類對象的原形,它不但包含了屬性的值,并且也同時包含了與該對象相關(guān)的一切方法。我們在創(chuàng)建相關(guān)的協(xié)義規(guī)則時,也同時制定了應(yīng)該如何解析該規(guī)則,XML和HTTP都只是傳輸了規(guī)則,卻無法傳輸規(guī)則的解析方法,而且這些規(guī)則必需是公開規(guī)定的。而通過指令對象的傳遞,不但可以傳遞規(guī)則,而且同時也傳遞了解析該規(guī)則的方法,并且還能夠通過完全地封裝一個或幾個指令對象,來完全地封裝起規(guī)則,只對外提供訪問的接口。 HTTP和XML等協(xié)義仍然需要一定的語法規(guī)則,在書寫時也必需按照該規(guī)則來書寫,而PPQ.DLL的對象傳遞是一種真正地?zé)o關(guān)性協(xié)義,它沒有任何的語法規(guī)則來限制。 讓我們再看一下PPQ.DLL為團隊開發(fā)所帶來的便利。在傳統(tǒng)的團隊開發(fā)模式中,雙方必需預(yù)先制定好要傳輸?shù)膮f(xié)義規(guī)則,然后開始各自編寫程序,如果一方需要改變或增加新的傳輸規(guī)則,他必需要通知其他的開發(fā)者,這個協(xié)議已經(jīng)改變啦,你必需要相應(yīng)地改變解碼程序。但是如果采用了PPQ.DLL的對象傳送,即使有任何一方改變了傳輸規(guī)則,也不用互相通知,因為解碼程序不需要改變,而且PPQ.DLL的宗旨是封裝,它強調(diào)將任務(wù)劃分成若干指令來完成,各個指令的組合用來完成不同的任務(wù),而各指令的實現(xiàn)功能可以被完全地封裝在指令內(nèi)部,與指令的交互,只是通過接口來完成。 傳輸指令對象的好處是很多的,無法在這里一一例舉出來,它是對傳統(tǒng)標(biāo)準(zhǔn)制定方式的一種挑戰(zhàn),使用這種方式,使所有的開發(fā)者都可以參與到標(biāo)準(zhǔn)的制定過程中,而且這種標(biāo)準(zhǔn)就象滾雪球一樣,會在自然地使用過程中變得越來越龐大,越來越規(guī)范,越來越充實,每一個開發(fā)者都不必再從最底層作起,他們可以從前人的基礎(chǔ)之上直接繼承或派生出新的應(yīng)用,以最快地速度開發(fā)出自己的程序。十一 PPQ.DLL的回調(diào)(鉤子)函數(shù)說明* 函數(shù)名稱:*typedef PBaseAct* (WINAPI *GOCALLBACK)(LPCTSTR lpszClassID)*參數(shù):*LPCTSTRlpszClassID-唯一標(biāo)識一個類的ID。*返回值:*PBaseAct*-返回新創(chuàng)建的對象。*說明:*這是一個鉤子函數(shù)。通過這個函數(shù)將得到用戶自定義的PBaseAct派生類的一個實例。注意:這是一個鉤子函數(shù),每一次的設(shè)定,都會被記錄下來。v1.02版以后,對算法進行了改進,不再按照順序來逐個調(diào)用所設(shè)定的鉤子函數(shù),鉤子函數(shù)的執(zhí)行和安裝順序沒有直接關(guān)系,DLL會直接調(diào)用處理該ClassID的鉤子函數(shù)??梢栽谝粋€鉤子函數(shù)中同時處理多個ClassID,每一個ClassID都必需公布,并且明確各訴哪些ClassID是必需的,是完成同一個任務(wù),哪些是完成另一個任務(wù)所必需的,哪一些是可有可無的。這樣其他開發(fā)者在設(shè)置鉤子函數(shù)時,才能夠根據(jù)自己的需要來決定應(yīng)該使用哪些類。舉例如下,其中Self1Act是自己定義的PBaseAct的派生類;USelf1Act是其它開發(fā)者定義的PBaseAct的派生類,本地必需有這兩個類的聲明。PBaseAct* WINAPI GlobalFunUserGetObject(LPCTSTR lpszClassID)if(memcmp(lpszClassID,B6FFC24C-7E13-11D0-9B47-00C04FC2F51D,PPQ_CLASS_ID_LEN)=0)/如果是自己定義的對象。return new Self1Act();else if(memcmp(lpszClassID,A9BEDC36-7E13-11D0-9B47-00C04FC2F51D,PPQ_CLASS_ID_LEN)=0)/加入對其他用戶創(chuàng)建的對象的支持。return new USelf1Act();return NULL;關(guān)于用戶自定義對象的健狀性問題與惡意性攻擊的解決辦法:如果你但心其他用戶會發(fā)送一個非法的對象,但是使用了在你在函數(shù)中規(guī)定的ClassID,你大可不必?fù)?dān)心。DLL通過以下兩種方法來防止這種惡意攻擊行為:1當(dāng)雙方建立連接的時候,都必需通過一個身份驗證的過程,這個過程中雙方傳遞的的指令對象是內(nèi)部定義好的指令對象,而且整個過程是外部不可干預(yù)的,只有通過身份驗證的雙方才會建立起連接,也就是說,建立連接的雙方都是相互信任的。2如果通過身份驗證的連接方要進行惡意攻擊,DLL還會通過第二種辦法自動丟棄這些錯誤的指令,絕對不會造成程序的非法操作。DLL在發(fā)現(xiàn)惡意性攻擊時,會記錄下攻擊的次數(shù),當(dāng)攻擊次數(shù)超過一定數(shù)量時,會向用戶發(fā)出警告,告訴用戶發(fā)出惡意攻擊的連接方的ID,并自動斷開該連接。* * * * * * * * * * * * *函數(shù)名稱:* typedef PFriend* (WINAPI* GETPALCALLBACK)(LPCTSTR lpszFriendID)*參數(shù):* LPCTSTR lpszFriendID -好友的ID標(biāo)識*返回值:* PFriend* -指向好友對象的指針。*說明:* 根據(jù)傳遞的好友ID返回指向具有該ID的PFriend對象的指針。* * * * * * * * * * * * *函數(shù)名稱:* typedef void (WINAPI *GETFILENCALLBACK)(DWORD dwFileID,PFriend* pFriend,CString* pstrFileN)*參數(shù):* DWORD dwFileID -請求的文件的數(shù)字標(biāo)識。* PFrined* pFriend -指向請求該文件的好友對象的指針。* CString* pstrFileN -指向保存文件數(shù)字標(biāo)識所對應(yīng)的實際文件名的指針。*返回值:* 無。*說明:* 該函數(shù)將根據(jù)傳遞的dwFileID,來得到實際所對應(yīng)的文件名。文件名保存在pstrFileN對象中。 如果函數(shù)執(zhí)行后*pstrFileN=,表示獲取實際文件失敗。 可以在這個回調(diào)函數(shù)中對文件編號進行校驗,決定好友是否有權(quán)得到該文件。 聲明: 對于文件采用數(shù)字標(biāo)識來表示,其最主要的目的是為了安全性,以及將來的擴展。 數(shù)字標(biāo)識如何與實際的文件名相對應(yīng),可以采用很多種辦法,因此并沒有包含在 這個DLL中。 關(guān)于數(shù)字標(biāo)識與實際文件名的對應(yīng)關(guān)系,將提供一個專門的類來實現(xiàn),這只是一種 解決辦法,大家可以自己去償試采用更好的辦法來解決這個問題。 下面是一種建立數(shù)字標(biāo)識與實際文件名的對應(yīng)關(guān)系的方式: 采用數(shù)據(jù)庫中記錄的存儲方式來保存每一個數(shù)字標(biāo)識與實際文件名的對應(yīng)關(guān)系,每 一個數(shù)字標(biāo)識與實際文件名的對應(yīng)關(guān)系相當(dāng)于一條記錄,數(shù)據(jù)被集中保存在一個文 件中,每一個記錄均是定長的,48個字節(jié)。 因為數(shù)字標(biāo)識所表示的文件可以是本地機器上的任何一個目錄下的任何一個文件,并

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論