使用 HTML5 WebSocket 構(gòu)建實時 Web 應用_第1頁
使用 HTML5 WebSocket 構(gòu)建實時 Web 應用_第2頁
使用 HTML5 WebSocket 構(gòu)建實時 Web 應用_第3頁
使用 HTML5 WebSocket 構(gòu)建實時 Web 應用_第4頁
使用 HTML5 WebSocket 構(gòu)建實時 Web 應用_第5頁
已閱讀5頁,還剩11頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

作為下一代的Web標準,HTML5擁有許多引人注目的新特性,如Canvas、本地存儲、多媒體編程接口、WebSocket等等。這其中有“Web的TCP"之稱的WebSocket格外吸引開發(fā)人員的注意。WebSocket的出現(xiàn)使得瀏覽器提供對Socket的支持成為可能,從而在瀏覽器和服務器之間提供了一個基于TCP連接的雙向通道。Web開發(fā)人員可以非常方便地使用WebSocket構(gòu)建實時web應用,開發(fā)人員的手中從此又多了一柄神兵利器。本文首先介紹HTML5WebSocket的基本概念以及這個規(guī)范試圖解決的問題,然后介紹WebSocket的基本原理和編程接口。接下來會通過一個簡單案例來示范怎樣實現(xiàn)一個WebSocket應用,并且展示W(wǎng)ebSocket如何在功能強大和編程簡單易用上達到的完美統(tǒng)一。最后介紹了目前主流瀏覽器對WebSocket支持的狀況、局限性以及未來的展望。實時Web應用的窘境Web應用的信息交互過程通常是客戶端通過瀏覽器發(fā)出一個請求,服務器端接收和審核完請求后進行處理并返回結(jié)果給客戶端,然后客戶端瀏覽器將信息呈現(xiàn)出來,這種機制對于信息變化不是特別頻繁的應用尚能相安無事,但是對于那些實時要求比較高的應用來說,比如說在線游戲、在線證券、設(shè)備監(jiān)控、新聞在線播報、RSS訂閱推送等等,當客戶端瀏覽器準備呈現(xiàn)這些信息的時候,這些信息在服務器端可能已經(jīng)過時了。所以保持客戶端和服務器端的信息同步是實時Web應用的關(guān)鍵要素,對Web開發(fā)人員來說也是一個難題。在WebSocket規(guī)范出來之前,開發(fā)人員想實現(xiàn)這些實時的Web應用,不得不采用一些折衷的方案,其中最常用的就是輪詢(Polling)和Comet技術(shù),而Comet技術(shù)實際上是輪詢技術(shù)的改進,又可細分為兩種實現(xiàn)方式,一種是長輪詢機制,一種稱為流技術(shù)。下面我們簡單介紹一下這幾種技術(shù):輪詢:這是最早的一種實現(xiàn)實時Web應用的方案??蛻舳艘砸欢ǖ臅r間間隔向服務端發(fā)出請求,以頻繁請求的方式來保持客戶端和服務器端的同步。這種同步方案的最大問題是,當客戶端以固定頻率向服務器發(fā)起請求的時候,服務器端的數(shù)據(jù)可能并沒有更新,這樣會帶來很多無謂的網(wǎng)絡傳輸,所以這是一種非常低效的實時方案。長輪詢:長輪詢是對定時輪詢的改進和提高,目地是為了降低無效的網(wǎng)絡傳輸。當服務器端沒有數(shù)據(jù)更新的時候,連接會保持一段時間周期直到數(shù)據(jù)或狀態(tài)改變或者時間過期,通過這種機制來減少無效的客戶端和服務器間的交互。當然,如果服務端的數(shù)據(jù)變更非常頻繁的話,這種機制和定時輪詢比較起來沒有本質(zhì)上的性能的提高。流:流技術(shù)方案通常就是在客戶端的頁面使用一個隱藏的窗口向服務端發(fā)出一個長連接的請求。服務器端接到這個請求后作出回應并不斷更新連接狀態(tài)以保證客戶端和服務器端的連接不過期。通過這種機制可以將服務器端的信息源源不斷地推向客戶端。這種機制在用戶體驗上有一點問題,需要針對不同的瀏覽器設(shè)計不同的方案來改進用戶體驗,同時這種機制在并發(fā)比較大的情況下,對服務器端的資源是一個極大的考驗。綜合這幾種方案,您會發(fā)現(xiàn)這些目前我們所使用的所謂的實時技術(shù)并不是真正的實時技術(shù),它們只是在用Ajax方式來模擬實時的效果,在每次客戶端和服務器端交互的時候都是一次HTTP的請求和應答的過程,而每一次的HTTP請求和應答都帶有完整的HTTP頭信息,這就增加了每次傳輸?shù)臄?shù)據(jù)量,而且這些方案中客戶端和服務器端的編程實現(xiàn)都比較復雜,在實際的應用中,為了模擬比較真實的實時效果,開發(fā)人員往往需要構(gòu)造兩個HTTP連接來模擬客戶端和服務器之間的雙向通訊,一個連接用來處理客戶端到服務器端的數(shù)據(jù)傳輸,一個連接用來處理服務器端到客戶端的數(shù)據(jù)傳輸,這不可避免地增加了編程實現(xiàn)的復雜度,也增加了服務器端的負載,制約了應用系統(tǒng)的擴展性。WebSocket的拯救HTML5WebSocket設(shè)計出來的目的就是要取代輪詢和Comet技術(shù),使客戶端瀏覽器具備像C/S架構(gòu)下桌面系統(tǒng)的實時通訊能力。瀏覽器通過JavaScript向服務器發(fā)出建立WebSocket連接的請求,連接建立以后,客戶端和服務器端就可以通過TCP連接直接交換數(shù)據(jù)。因為WebSocket連接本質(zhì)上就是一個TCP連接,所以在數(shù)據(jù)傳輸?shù)姆€(wěn)定性和數(shù)據(jù)傳輸量的大小方面,和輪詢以及Comet技術(shù)比較,具有很大的性能優(yōu)勢。W網(wǎng)站對傳統(tǒng)的輪詢方式和WebSocket調(diào)用方式作了一個詳細的測試和比較,將一個簡單的Web應用分別用輪詢方式和WebSocket方式來實現(xiàn),在這里引用一下他們的測試結(jié)果圖:MM1.COO.IXKJ2m加刪90n.G0D.CMM]UseA□rexmUse-CaseC■MM1.COO.IXKJ2m加刪90n.G0D.CMM]UseA□rexmUse-CaseC■BOEBOD,MO□ i.6D0.M)OUseB■€9SBOJCCDG16OJOO0口Pollinfl□WebSeek圖1.輪詢和WebSocket實現(xiàn)方式的網(wǎng)絡負載對比圖通過這張圖可以清楚的看出,在流量和負載增大的情況下,WebSocket方案相比傳統(tǒng)的Ajax輪詢方案有極大的性能優(yōu)勢。這也是為什么我們認為WebSocket是未來實時Web應用的首選方案的原因。WebSocket規(guī)范WebSocket協(xié)議本質(zhì)上是一個基于TCP的協(xié)議。為了建立一個WebSocket連接,客戶端瀏覽器首先要向服務器發(fā)起一個HTTP請求,這個請求和通常的HTTP請求不同,包含了一些附加頭信息,其中附加頭信息”Upgrade:WebSocket”表明這是一個申請協(xié)議升級的HTTP請求,服務器端解析這些附加的頭信息然后產(chǎn)生應答信息返回給客戶端,客戶端和服務器端的WebSocket連接就建立起來了,雙方就可以通過這個連接通道自由的傳遞信息,并且這個連接會持續(xù)存在直到客戶端或者服務器端的某一方主動的關(guān)閉連接。下面我們來詳細介紹一下WebSocket規(guī)范,由于這個規(guī)范目前還是處于草案階段,版本的變化比較快,我們選擇draft-hixie-thewebsocketprotocol-76版本來描述WebSocket協(xié)議。因為這個版本目前在一些主流的瀏覽器上比如Chrome,、FireFox、Opera上都得到比較好的支持,您如果參照的是新一些的版本話,內(nèi)容可能會略有差別。一個典型的WebSocket發(fā)起請求和得到響應的例子看起來如下:清單1.WebSocket握手協(xié)議i客戶端到服務端:GET/demoHTTP/1.1Host:Connection:UpgradeSec-WebSocket-Key2:129985Y31.POOUpgrade:WebSocketSec-WebSocket-Key1:4@146546xW%0l15Origin:[8-bytesecuritykey]11服務端到客戶端:HTTP/1.1101WebSocketProtocolHandshakeUpgrade:WebSocketConnection:UpgradeWebSocket-Origin:WebSocket-Location:ws:///demo[16-bytehashresponse]這些請求和通常的HTTP請求很相似,旦是其中有些內(nèi)容是和WebSocket協(xié)議密切相關(guān)的。我們需要簡單介紹一下這些請求和應答信息,"Upgrade:WebSocket"表示這是一個特殊的HTTP請求,請求的目的就是要將客戶端和服務器端的通訊協(xié)議從HTTP協(xié)議升級到WebSocket協(xié)議。從客戶端到服務器端請求的信息里包含有”Sec-WebSocket-Key1”、“Sec-WebSocket-Key2”和”[8-bytesecuritykey]"這樣的頭信息。這是客戶端瀏覽器需要向服務器端提供的握手信息,服務器端解析這些頭信息,并在握手的過程中依據(jù)這些信息生成一個16位的安全密鑰并返回給客戶端,以表明服務器端獲取了客戶端的請求,同意創(chuàng)建WebSocket連接。一旦連接建立,客戶端和服務器端就可以通過這個通道雙向傳輸數(shù)據(jù)了。在實際的開發(fā)過程中,為了使用WebSocket接口構(gòu)建Web應用,我們首先需要構(gòu)建一個實現(xiàn)了WebSocket規(guī)范的服務器,服務器端的實現(xiàn)不受平臺和開發(fā)語言的限制,只需要遵從WebSocket規(guī)范即可,目前已經(jīng)出現(xiàn)了一些比較成熟的WebSocket服務器端實現(xiàn),比如:KaazingWebSocketGateway—一個Java實現(xiàn)的WebSocketServermod_pywebsocket一—個Python實現(xiàn)的WebSocketServerNetty一一個Java實現(xiàn)的網(wǎng)絡框架其中包括了對WebSocket的支持node.js一一個Server端的JavaScript框架提供了對WebSocket的支持

如果以上的WebSocket服務端實現(xiàn)還不能滿足您的業(yè)務需求的話,開發(fā)人員完全可以根據(jù)WebSocket規(guī)范自己實現(xiàn)一個服務器。在“WebSocket實戰(zhàn)”這一節(jié),我們將使用Microsoft.NET平臺上的C#語言來打造一個簡單的WebSocket服務器,繼而構(gòu)建一個簡單的實時聊天系統(tǒng)。WebSocketJavaScript接口上一節(jié)介紹了WebSocket規(guī)范,其中主要介紹了WebSocket的握手協(xié)議。握手協(xié)議通常是我們在構(gòu)建WebSocket服務器端的實現(xiàn)和提供瀏覽器的WebSocket支持時需要考慮的問題,而針對Web開發(fā)人員的WebSocketJavaScript客戶端接口是非常簡單的,以下是WebSocketJavaScript接口的定義:清單2?WebSocketJavaScript定義[Constructor(inDOMStringurl,inoptionalDOMStringprotocol)]interfaceWebSocket{readonlyattributeDOMStringURL;4//readystateconstunsignedshortCONNECTING=0;constunsignedshortOPEN=1;constunsignedshortCLOSED=2;readonlyattribute unsignedshort readyState;readonlyattribute unsignedlong bufferedAmount;□//networkingattributeFunction onopen;attributeFunction onmessage;attributeFunction onclose;14booleansend(inDOMStringdata);15voidclose();16};17WebSocketimplementsEventTarget;毎其中URL屬性代表WebSocket服務器的網(wǎng)絡地址,協(xié)議通常是”ws”,send方法就是發(fā)送數(shù)據(jù)到服務器端,close方法就是關(guān)閉連接。除了這些方法,還有一些很重要的事件:

onopen,onmessage,onerror以及onclose。我們借用Nettuts網(wǎng)站上的一張圖來形象的展示一下WebSocket接口:onerroronmes^ageonopenoncloseofMtbsork-vfiCn^tTEa^*-livrlbuc:onerroronmes^ageonopenoncloseofMtbsork-vfiCn^tTEa^*-livrlbuc:#Puii(tlc?n阿匪p?n;<1ttrLhuE:D伽Etlanc^ownagB:AttrLbutnFtincl;IonNi?xE^ar;FU兩伽圖2?WebSocketJavaScript接口下面是一段簡單的JavaScript代碼展示了怎樣建立WebSocket連接和獲取數(shù)據(jù):清單3.建立WebSocket連接的實例JavaScript代碼1varwsServer='ws://localhost:8888/Demo';2varwebsocket=newWebSocket(wsServer);websocket.onopen=function(evt){onOpen(evt)};websocket.onclose=function(evt){onClose(evt)};websocket.onmessage=function(evt){onMessage(evt)};websocket.onerror=function(evt){onError(evt)};7functiononOpen(evt){console.log("ConnectedtoWebSocketserver?");TOC\o"1-5"\h\z}10functiononClose(evt){console.log("Disconnected");}13functiononMessage(evt){console.log('Retrieveddatafromserver:'+evt.data);}16functiononError(evt){console.log('Erroroccured:'+evt.data);}

瀏覽器支持卜面是主流瀏覽器對HTML5WebSocket的支持情況:瀏覽器支持情況ChromeSupportedinversion4+FirefoxSupportedinversion4+InternetExplorerSupportedinversion10+OperaSupportedinversion10+SafariSupportedinversion5+WebSocket實戰(zhàn)這一節(jié)里我們用一個案例來演示怎么使用WebSocket構(gòu)建一個實時的Web應用。這是一個簡單的實時多人聊天系統(tǒng),包括客戶端和服務端的實現(xiàn)??蛻舳送ㄟ^瀏覽器向聊天服務器發(fā)起請求,服務器端解析客戶端發(fā)出的握手請求并產(chǎn)生應答信息返回給客戶端,從而在客戶端和服務器之間建立連接通道。服務器支持廣播功能,每個聊天用戶發(fā)送的信息會實時的發(fā)送給所有的用戶,當用戶退出聊天室時,服務器端需要清理相應用戶的連接信息,避免資源的泄漏。以下我們分別從服務器端和客戶端來演示這個Web聊天系統(tǒng)的實現(xiàn),在實現(xiàn)方式上我們采用了C#語言來實現(xiàn)WebSocket服務器,而客戶端是一個運行在瀏覽器里的HTML文件。WebSocket服務器端實現(xiàn)這個聊天服務器的實現(xiàn)和基于套接字的網(wǎng)絡應用程序非常類似,首先是服務器端要啟動一個套接字監(jiān)聽來自客戶端的連接請求,關(guān)鍵的區(qū)別在于WebSocket服務器需要解析客戶端的WebSocket握手信息,并根據(jù)WebSocket規(guī)范的要求產(chǎn)生相應的應答信息。一旦WebSocket連接通道建立以后,客戶端和服務器端的交互就和普通的套接字網(wǎng)絡應用程序是一樣的了。所以在下面的關(guān)于WebSocket服務器端實現(xiàn)的描述中,我們主要闡述WebSocket服務器怎樣處理WebSocket握手信息,至于WebSocket監(jiān)聽端口的建立,套接字信息流的讀取和寫入,都是一些常用的套接字編程的方式,我們就不多做解釋了,您可以自行參閱本文的附件源代碼文件。在描述WebSocket規(guī)范時提到,—個典型的WebSocketUpgrade信息如下所示:翁GET/demoHTTP/1.1Host:Connection:UpgradeSec-WebSocket-Key2:129985Y31.POOUpgrade:WebSocketSec-WebSocket-Key1:4@146546xW%0l15Origin:[8-bytesecuritykey]翁其中Sec-WebSocket-Key1,Sec-WebSocket-Key2和[8-bytesecuritykey]這幾個頭信息是WebSocket服務器用來生成應答信息的來源,依據(jù)draft-hixie-thewebsocketprotocol-76 草案的定義,WebSocket服務器基于以下的算法來產(chǎn)生正確的應答信息:1.逐個字符讀取Sec-WebSocket-Key1頭信息中的值,將數(shù)值型字符連接到一起放到一個臨時字符串里,同時統(tǒng)計所有空格的數(shù)量;2?將在第1步里生成的數(shù)字字符串轉(zhuǎn)換成一個整型數(shù)字,然后除以第1步里統(tǒng)計出來的空格數(shù)量,將得到的浮點數(shù)轉(zhuǎn)換成整數(shù)型;3?將第2步里生成的整型值轉(zhuǎn)換為符合網(wǎng)絡傳輸?shù)木W(wǎng)絡字節(jié)數(shù)組;4.對Sec-WebSocket-Key2頭信息同樣進行第1到第3步的操作,得到另外一個網(wǎng)絡字節(jié)數(shù)組;

5?將[8-bytesecuritykey]和在第3,第4步里生成的網(wǎng)絡字節(jié)數(shù)組合并成一個16字節(jié)的數(shù)組;6.對第5步生成的字節(jié)數(shù)組使用MD5算法生成一個哈希值,這個哈希值就作為安全密鑰返回給客戶端,以表明服務器端獲取了客戶端的請求,同意創(chuàng)建WebSocket連接至此,客戶端和服務器的WebSocket握手就完成了,WebSocket通道也建立起來了。下面首先介紹一下服務器端實現(xiàn)是如何根據(jù)用戶傳遞的握手信息來生成網(wǎng)絡字節(jié)數(shù)組的o.NET平臺提供了很方便的對字符串,數(shù)值以及數(shù)組操作的函數(shù),所以生成字節(jié)數(shù)組的方法還是非常簡單明了的,代碼如下:清單4.生成網(wǎng)絡字節(jié)數(shù)組的代碼privatebyte[]BuildServerPartialKey(stringclientKey){stringpartialServerKey="";4byte[]currentKey;5intspacesNum=0;6char[]keyChars=clientKey.ToCharArray();foreachcharcurrentCharinkeyChars)TOC\o"1-5"\h\z{9if(char.IsDigit(currentChar))partialServerKey+=currentChar;10if(char.IsWhiteSpace(currentChar))spacesNum++;11 }12try{currentKey=BitConverter.GetBytes((int)(Int64.Parse(partialServerKey)/spacesNum));16if(BitConverter.IsLittleEndian)Array.Reverse(currentKey);17 }18catch19 {20if(currentKey!=null)Array.Clear(currentKey,0,currentKey.Length);

22returncurrentKey;23 }%得到網(wǎng)絡字節(jié)數(shù)組以后,服務器端生成16位安全密鑰的方法如下所示:清單5.生成16位安全密鑰的代碼跆1privatebyte[]BuildCompleteServerKey(byte[]serverKeyl,byte[]serverKey2,2byte[]last8Bytes)3 {4byte[]concatenatedKeys=newbyte[16];5Array.Copy(serverKey1,0,concatenatedKeys,0,4);6Array.Copy(serverKey2,0,concatenatedKeys,4,4);7Array.Copy(last8Bytes,0,concatenatedKeys,8,8);System.Security.Cryptography.MD5MD5Service=System.Security.Cryptography.MD5.Create();10returnMD5Service.ComputeHash(concatenatedKeys);11}翁整個實現(xiàn)是非常簡單明了的,就是將生成的網(wǎng)絡字節(jié)數(shù)組和客戶端提交的頭信息里的[8-bytesecuritykey]合并成一個16位字節(jié)數(shù)組并用MD5算法加密,然后將生成的安全密鑰作為應答信息返回給客戶端,雙方的WebSocekt連接通道就建立起來了。實現(xiàn)了WebSocket握手信息的處理邏輯,一個具有基本功能的WebSocket服務器就完成了。整個WebSocket服務器由兩個核心類構(gòu)成,一個是WebSocketServer,另外一個是SocketConnection,出于篇幅的考慮,我們不介紹每個類的屬性和方法了,文章的附件會給出詳細的源代碼,有興趣的讀者可以參考。服務器剛啟動時的畫面如下:圖3?WebSocket服務器剛啟動的畫面客戶端可以依據(jù)這個信息填寫聊天服務器的連接地址,當有客戶端連接到聊天服務器上時,服務器會打印出客戶端和服務器的握手信息,每個客戶的聊天信息也會顯示在服務器的界面上,運行中的聊天服務器的界面如下:國G'WbDOW戢杯g"扭訶Ed?炯為怕潼丨冬常豐.左口二ifsJJ金“叩和.正在準盡連檜…■GET/ehatHTTP/1.1:3.11S-i5S.157:4iConnDctiorisUpgradaOrigin:;]可1Sr(□S&q)3Upgrade:blsbSccketW&bSo?ket-K?y2:9,650 -S笈送握手信M"…4TTP/1I 1i?1?申耳 H"巧中沖“口岡特up^rad?:冊^bs^ckotCcphfibgtiontUpgradeS-^c^lilebSocket^Origin:file://^.^c-U?h£oek&t-Locatiorb:ueq://-S.119.135?127:4141/chat接:矍到的銜忌risgini黃曉聶料圖4.有客戶端連接到WebSocket服務器的以上我們簡單描述了實現(xiàn)一個WebSocket服務器的最基本的要素,下一節(jié)我們會描述客戶端的實現(xiàn)??蛻舳藢崿F(xiàn)客戶端的實現(xiàn)相對于服務器端的實現(xiàn)來說要簡單得多了,我們只需要發(fā)揮想象去設(shè)計HTML用戶界面,然后呼叫WebSocketJavaScript接口來和WebSocket服務器端來交互就可以了。當然別忘了使用一個支持HTML5和WebSocket的瀏覽器,在筆者寫這篇文章的時候使用的瀏覽器是Firefox。客戶端的頁面結(jié)構(gòu)是非常簡潔的,初始運行界面如下:圖5.聊天室客戶端初始頁面當頁面初次加載的時候,首先會檢測當前的瀏覽器是否支持WebSocket并給出相應的提示信息。用戶按下連接按鈕時,頁面會初始化一個到聊天服務器的WebSocekt連接,初始化成功以后,頁面會加載對應的WebSocket事件處理函數(shù),客戶端JavaScript代碼如下所示:清單6.初始化客戶端WebSocket對象的代碼[functionToggleConnectionClicked(){2if(SocketCreated&&(ws.readyState==0||ws.readyState==1)) {ws.close();else{Lo準備連接到聊天服務器...");6try{7 ws=8newWebSocket("ws://"+document.getElementById("Connection").value);SocketCreatedtrue;catch(ex){Log(ex,"ERROR");12return;}document.getElementById("ToggleConnection").innerHTML 斷開"?ws.onopen=WSonOpen;ws.onmessage=WSonMessage;

17ws.onclose=WSonClose;18ws.onerror=WSonError;19}20};2122functionWSonOpen(){23Log連接已經(jīng)建立。","OK");24$("#SendDataContainer").show("slow");25};2627functionWSonMessage(event){28Log(event.data);2930};31functionWSonClose(){32Log連接關(guān)閉。","ERROR");33document.getElementById("ToggleConnection").innerHTML=連接";34$("#SendDataContainer").hide("slow");35};363738functionWSonError(){39Log("WebSocke錯誤。","ERROR");40};當用戶按下發(fā)送按鈕,客戶端會調(diào)用WebSocket對象向服務器發(fā)送信息,并且這個消息會廣播給所有的用戶,實現(xiàn)代碼如下所示:functionSendDataClicked()2{TOC\o"1-5"\h\z3if(docu

溫馨提示

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

評論

0/150

提交評論