版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、<p><b> 目錄</b></p><p> Ⅰ需求分析 ……………………………………………………………………………5</p><p> 1.1課程設(shè)計(jì)目的 ……………………………………………………………………5</p><p> 1.2課程設(shè)計(jì)要求 ……………………………………………………………………5</p&g
2、t;<p> 1.3選題與操作流程 …………………………………………………………………5</p><p> 1.4開發(fā)環(huán)境與開發(fā)平臺(tái) ……………………………………………………………5</p><p> ?、蚩傮w設(shè)計(jì) ……………………………………………………………………………5</p><p> 2.1總體設(shè)計(jì)概念 ……………………………………
3、………………………………5</p><p> 2.2系統(tǒng)功能 …………………………………………………………………………5</p><p> 2.3系統(tǒng)架構(gòu) …………………………………………………………………………6</p><p> 2.4 模塊劃分 …………………………………………………………………………6</p><p> ?、?/p>
4、詳細(xì)設(shè)計(jì) ……………………………………………………………………………6</p><p> 3.1軟件層次模型 ……………………………………………………………………6</p><p> 3.2協(xié)議結(jié)構(gòu) …………………………………………………………………………6</p><p> 3.3數(shù)據(jù)流程圖 ………………………………………………………………………8&
5、lt;/p><p> Ⅳ系統(tǒng)實(shí)現(xiàn)編碼及運(yùn)行結(jié)果 …………………………………………………………9</p><p> 4.1服務(wù)器端設(shè)計(jì)與編碼 ……………………………………………………………9</p><p> 4.2客戶端設(shè)計(jì)與編碼 ………………………………………………………………11</p><p> 4.3運(yùn)行結(jié)果 ………………
6、…………………………………………………………12</p><p> Ⅴ結(jié)論與總結(jié) …………………………………………………………………………19</p><p> 5.1課程設(shè)計(jì)結(jié)論 …………………………………………………………………… 20</p><p> 5.2課程設(shè)計(jì)總結(jié)與體會(huì) ……………………………………………………………20</p>
7、<p> ?、稣n程設(shè)計(jì)分工及參考文獻(xiàn) …………………………………………………………20</p><p> 6.1課程設(shè)計(jì)分工 ……………………………………………………………………20</p><p> 6.2參考文獻(xiàn) …………………………………………………………………………21</p><p> ?、鞲戒?………………………………………………………
8、………………………22</p><p> 關(guān)鍵代碼……………………………………………………………………… 22</p><p><b> ?、?需求分析</b></p><p><b> 1.1課程設(shè)計(jì)目的</b></p><p> 本次計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì),旨在通過該課程設(shè)計(jì),使學(xué)生了解、掌握
9、TCP、UDP協(xié)議的原理;了解、掌握Socket編程的方法;了解、掌握應(yīng)用協(xié)議設(shè)計(jì)的思想;利用Winsock API或者Java Socket API編制一個(gè)能部署在Internet上的點(diǎn)對點(diǎn)數(shù)據(jù)交換(P2P)、HTTP/FTP服務(wù)器系統(tǒng)、共享白板。</p><p><b> 1.2課程設(shè)計(jì)要求</b></p><p> 要求每組學(xué)生從上述3個(gè)系統(tǒng)中任選一個(gè),獨(dú)立
10、完成系統(tǒng)的功能設(shè)計(jì)和實(shí)現(xiàn),使所實(shí)現(xiàn)的系統(tǒng)可以能夠包含主要的內(nèi)容要求,并要求學(xué)生必須在報(bào)告中明確具體分工情況。</p><p> 1.3選題與操作流程</p><p> 在網(wǎng)絡(luò)越來越發(fā)達(dá)的今天,人們對網(wǎng)絡(luò)的依賴越來越多,越來越離不開網(wǎng)絡(luò),由此而產(chǎn)生的聊天工具越來越多,類似QQ、網(wǎng)絡(luò)聊天時(shí)一類的聊天系統(tǒng)的發(fā)展日新月異。因此,基于我們實(shí)際的知識結(jié)構(gòu)構(gòu)成以及網(wǎng)絡(luò)聊天在當(dāng)今時(shí)代的盛行趨勢,本課程
11、設(shè)計(jì)小組選擇了課程設(shè)計(jì)題目點(diǎn)對點(diǎn)數(shù)據(jù)交換(P2P),用于實(shí)現(xiàn)基于服務(wù)器轉(zhuǎn)發(fā)的任意多點(diǎn)間的數(shù)據(jù)共享與交換。其具體設(shè)計(jì)內(nèi)容如下:</p><p> 1)類似P2P的QQ聊天系統(tǒng),有客戶端和服務(wù)器端。</p><p> 2)服務(wù)器端記錄當(dāng)前在線客戶列表,把客戶列表發(fā)送給每一個(gè)在線客戶,并實(shí)時(shí)刷新。</p><p> 3)任一個(gè)客戶可以和任意其它的客戶進(jìn)行交互,即從在
12、線客戶列表中選擇一個(gè)或一組其它客戶通過服務(wù)器轉(zhuǎn)發(fā)彼此進(jìn)行交互,包括信息交互,文件交互。</p><p><b> ?、蚩傮w設(shè)計(jì)</b></p><p><b> 2.1總體設(shè)計(jì)概念</b></p><p> 為實(shí)現(xiàn)網(wǎng)絡(luò)聊天的功能,采用Java Socket編程,服務(wù)器與客戶端采用了TCP/IP連接方式,在設(shè)計(jì)聊天方案時(shí)
13、,實(shí)行將所有信息發(fā)往服務(wù)器端,再由服務(wù)器進(jìn)行分別處理的思路,服務(wù)器端是所有信息的中心。</p><p> 服務(wù)器端可以查看所有用戶的聊天記錄,監(jiān)控所有用戶的狀態(tài),發(fā)出用戶上線提示等公告,客戶端則提供接收公告的功能。</p><p><b> 2.2系統(tǒng)功能</b></p><p> 本課程設(shè)計(jì)按照實(shí)驗(yàn)的具體要求,首先應(yīng)用Socket編程創(chuàng)
14、建客戶端和服務(wù)器端,它們之間通過一個(gè)交互的連接來實(shí)現(xiàn)數(shù)據(jù)通信;然后在客戶端 設(shè)置一個(gè)監(jiān)聽器,用于監(jiān)聽服務(wù)器發(fā)來的消息;最后在客戶端設(shè)置點(diǎn)對點(diǎn)的文件交互需要用到的接受和發(fā)送類,以及表征文件傳輸過程的進(jìn)度條。</p><p><b> 2.3系統(tǒng)架構(gòu)</b></p><p> 1)選擇傳輸控制協(xié)議TCP,使用Java的Socket編程機(jī)制,分別建立客戶端與服務(wù)器端;&
15、lt;/p><p> 2)分別設(shè)計(jì)客戶端與服務(wù)器端的界面,并使用Java應(yīng)用程序用戶界面的開發(fā)工具包Swing進(jìn)行窗體界面的布局,以及實(shí)現(xiàn)部分窗口事件的相應(yīng)。</p><p><b> 2.4 模塊劃分</b></p><p> 1)服務(wù)器端,主要實(shí)現(xiàn)向各個(gè)客戶端發(fā)布系統(tǒng)消息,接受來自客戶端的各種信息并分別處理。具體功能如下:</p&g
16、t;<p><b> ?、龠B接控制:</b></p><p><b> ?、诠芾碜饔茫?lt;/b></p><p><b> ?、鬯⑿铝斜恚?lt;/b></p><p><b> ?、艿顷懶畔ⅲ?lt;/b></p><p><b>
17、⑤聊天記錄:</b></p><p><b> ?、尴⑻幚恚?lt;/b></p><p> 2)客戶端:主要實(shí)現(xiàn)向服務(wù)器端發(fā)布消息,并且對來自服務(wù)器的消息做出相應(yīng)的響應(yīng)。具體功能如下:</p><p><b> ?、龠B接功能:</b></p><p><b> ?、诘卿浽O(shè)
18、置:</b></p><p><b> ?、郾O(jiān)聽作用:</b></p><p><b> ④消息處理:</b></p><p><b> ?、萘奶煊涗洠?lt;/b></p><p><b> ?、尴⑻幚恚?lt;/b></p>
19、<p><b> ⑦傳輸進(jìn)度:</b></p><p><b> ?、辔募鬏敚?lt;/b></p><p><b> Ⅲ 詳細(xì)設(shè)計(jì)</b></p><p><b> 3.1軟件層次模型</b></p><p> 服務(wù)器層次結(jié)構(gòu)和客戶端
20、層次結(jié)構(gòu)。</p><p><b> 3.2協(xié)議結(jié)構(gòu)</b></p><p> 在Java socket通信中使用的協(xié)議是TCP協(xié)議。TCP協(xié)議是TCP/IP協(xié)議中面向連接的運(yùn)輸層協(xié)議,它提供全雙工的和可靠交付的服務(wù)。由于通信是全雙工方式,因此TCP連接的任何一方都能夠發(fā)送和接收數(shù)據(jù)。發(fā)送端的應(yīng)用進(jìn)程按照自己產(chǎn)生數(shù)據(jù)的規(guī)律,不斷地將數(shù)據(jù)塊(其長短可能各異)陸續(xù)寫入
21、到TCP的發(fā)送緩存中。TCP再從發(fā)送緩存中取出一定數(shù)量的數(shù)據(jù),將其組成TCP報(bào)文段逐個(gè)傳給IP層,然后發(fā)送出去。接收端從IP層收到TCP報(bào)文段后,先將其存在接收緩存中,然后讓接收端的進(jìn)程從接收緩存中將數(shù)據(jù)塊逐個(gè)讀取。 </p><p> TCP協(xié)議的報(bào)文分為首部和數(shù)據(jù)兩個(gè)部分。眾所周知首部中含有源端口、目的端口、序號、確認(rèn)號等內(nèi)容。因此在利用socket通信時(shí),要想實(shí)現(xiàn)不同的功能和數(shù)據(jù)傳輸,包括指令和純數(shù)據(jù)的傳
22、輸,可以通過在TCP報(bào)文的數(shù)據(jù)部分進(jìn)行再分段來實(shí)現(xiàn)。由此指定一些套接字,并接利用這些套接字來對不同的數(shù)據(jù)進(jìn)行分段,這樣就能輕松地將提取所需數(shù)據(jù)以實(shí)現(xiàn)不同功能。</p><p> 本課程設(shè)計(jì)正是利用上述方法來建立一個(gè)基于TCP協(xié)議的協(xié)議。這個(gè)協(xié)議的主要組成部分為套接字及數(shù)據(jù)段。在程序中主要使用的套接字有:“NICKNAME:”、“SPECIAL:”、“$SPECIAL$”、“FLENGTH:”、“FILEECHO
23、:”以及“FILE:”等。其中各個(gè)套接字又有不同的使用方法。</p><p> 如果數(shù)據(jù)沒有使用套接字,則就被默認(rèn)為這一數(shù)據(jù)是廣播數(shù)據(jù)及聊天室的公開數(shù)據(jù),這樣的數(shù)據(jù)將會(huì)全部傳給聊天室里的各個(gè)用戶并且會(huì)保存在聊天室服務(wù)器里。</p><p> 如果使用的是“NICKNAME:”,則其后數(shù)據(jù)為發(fā)此數(shù)據(jù)者所要變更的昵稱。</p><p> 另外,將“$SPECIAL
24、$”當(dāng)作劃分兩個(gè)數(shù)據(jù)的套接字,通常在一個(gè)套接字之后有兩種數(shù)據(jù)的情況下使用。</p><p> 如果使用的是“SPECIAL:”,則其后數(shù)據(jù)至“$SPECIAL$”之間的為目的昵稱,而在“$SPECIAL$”之后的則為所要傳輸?shù)男畔?shù)據(jù),同時(shí)我們擬定這個(gè)套接字為私聊套接字,雖通過服務(wù)器轉(zhuǎn)發(fā)但其內(nèi)容不會(huì)在服務(wù)器上顯示。</p><p> 若套接字為“FILE:”,則表示該用戶發(fā)出了一個(gè)對一
25、的客戶文件傳送請求,此時(shí),服務(wù)器端同樣通過控制字頭后的昵稱,查找到對應(yīng)的接收端用戶的信息,并將該用戶的IP地址傳遞給發(fā)送端,并在服務(wù)器端顯示發(fā)送端想要對接收端傳輸文件的信息。協(xié)議格式如下:“FILE:”+目的昵稱+“$FILE$”+文件名稱。</p><p> 若套接字為“FILEFINISH:”,則表示客戶之間文件傳輸完畢,此時(shí)服務(wù)器端發(fā)出文件傳輸完畢的信息。</p><p> “F
26、LENGTH:”的套接字表示文件長度,其格式為“FLENGTH:”+目的昵稱+“$SPECIAL$”+文件長度。這樣我們在文件傳輸過程中就可以知道所接收文件的大小同時(shí)有益于進(jìn)度條的使用。</p><p> 套接字“FILEECHO:”是為服務(wù)器發(fā)給客戶端的目的地的IP地址。</p><p> 使用套接字的方法能夠把控制信息和數(shù)據(jù)部分一起傳送達(dá)到服務(wù)器和客戶端的不同溝通,這樣我們就可以利
27、用服務(wù)器來完成我們所需的各個(gè)服務(wù),無論公開聊天還是私下聊天都可以,同時(shí)還能在某種意義上保護(hù)隱私。這個(gè)socket的協(xié)議就是利用TCP協(xié)議的數(shù)據(jù)流、面向連接和全雙通來實(shí)現(xiàn)的。</p><p><b> 3.3數(shù)據(jù)流程圖</b></p><p> 根據(jù)以上的程序模塊劃分,設(shè)計(jì)好服務(wù)器端和客戶端的流程圖,如下:</p><p><b>
28、 ?、俜?wù)器端流程:</b></p><p><b> ?、诳蛻舳肆鞒虉D:</b></p><p> ?、?系統(tǒng)實(shí)現(xiàn)編碼及運(yùn)行結(jié)果</p><p> 4.1服務(wù)器端設(shè)計(jì)與編碼</p><p> 4.1.1 服務(wù)器程序</p><p> 該段功能由Server.java文件中的Se
29、rver類實(shí)現(xiàn)(程序代碼請見附錄),具體實(shí)現(xiàn)過程如下:</p><p> ?、賳?dòng)服務(wù)并接收連接:服務(wù)器的任務(wù)首先是建立一個(gè)由IP地址到昵稱的映射的哈希表,用于存放用戶的基本信息;啟動(dòng)服務(wù)器后,等候建立一個(gè)連接,然后用這個(gè)連接產(chǎn)生的Socket創(chuàng)建一個(gè)Client,同時(shí)檢查該用戶是否已存在哈希表中,若以存在,則提示該次連接請求失敗,從而實(shí)現(xiàn)限制IP的目的;若不存在,則將該IP地址及其昵稱或默認(rèn)昵稱的映射添加到哈希
30、表中,接著服務(wù)器端向所有的用戶發(fā)送管理信息,提示有新的用戶登錄,并且將刷新后的用戶列表同時(shí)發(fā)送到各個(gè)客戶端。</p><p> ②關(guān)閉服務(wù):服務(wù)器端遍歷哈希表,關(guān)掉每一個(gè)用戶對應(yīng)的Socket,之后,關(guān)閉服務(wù)Server。</p><p> ?、酃芾碜饔弥l(fā)送消息: 服務(wù)器端解析由客戶端發(fā)送的請求,若控制字以“SPECIAL”開頭,則通過控制字后的昵稱從哈希表中找到對應(yīng)的用戶,實(shí)現(xiàn)服務(wù)器
31、端到客戶端的點(diǎn)對點(diǎn)消息交互;若不是以“SPECIAL”開頭,則實(shí)現(xiàn)消息的廣播發(fā)布。</p><p> ?、芄芾碜饔弥薷年欠Q:首先判斷新的昵稱是否在哈希表中存在,若已存在則給出錯(cuò)誤提示,否則通過該用戶的舊昵稱在哈希表中查找到該用戶,并用欲修改的昵稱替換掉原昵稱;接著刷新服務(wù)器端的用戶列表顯示,最后刷新客戶端的用戶列表顯示。</p><p> ?、莨芾碜饔弥?dāng)嚅_連接:若要斷開某個(gè)客戶端與服務(wù)
32、器的連接,首先向該用戶發(fā)送被管理員請出系統(tǒng)的信息,然后通過該用戶的昵稱從哈希表中找到對應(yīng)socket、service及IP地址等信息,再從每一項(xiàng)信息對應(yīng)的列表里刪除該用戶的信息,最后關(guān)閉該用戶的socket,同時(shí)刷新服務(wù)器端以及各個(gè)客戶端的用戶列表顯示。</p><p> ?、拊诜?wù)其中,需要同時(shí)處理多個(gè)客戶端的請求,因此此處用到了多線程處理機(jī)制。在服務(wù)器程序里創(chuàng)建單個(gè)Server Socket,并調(diào)用accep
33、t()來等候一個(gè)新連接,一旦accept()返回,就取得結(jié)果獲得的socket,并用它新建一個(gè)線程,令其只為那個(gè)特定的客戶端服務(wù),然后再調(diào)用accept(),等候下一次新的連接請求。</p><p><b> 4.1.2功能函數(shù)</b></p><p> 該段功能由ChatTookit.java文件中的ChatTookit類實(shí)現(xiàn)(程序代碼請見附錄),具體實(shí)現(xiàn)過程如
34、下:</p><p> ?、俸瘮?shù)getAllNickname:該函數(shù)實(shí)現(xiàn)從IP地址——昵稱對照哈希表中得到所有的昵稱的功能,函數(shù)原型如下:</p><p> public static String getAllNickname(Hashtable ip2nickname)</p><p> ?、诤瘮?shù)sendInfoToAll:該函數(shù)實(shí)現(xiàn)遍歷所有已連接的客戶端,并
35、且發(fā)送輸入的信息的功能,函數(shù)原型如下:</p><p> public static void sendInfoToAll(ArrayList onLineUsers,String info) throws IOException</p><p> ?、酆瘮?shù)sendInfo:該函數(shù)實(shí)現(xiàn)給某個(gè)特定用戶發(fā)送一條信息的功能,函數(shù)原型如下:</p><p> publ
36、ic static void sendInfo(Socket client,String info) throws IOException</p><p> ?、芎瘮?shù)getIP:該函數(shù)實(shí)現(xiàn)從socket中得到用戶的ip地址的功能,函數(shù)原型如下:</p><p> public static String getIP(Socket socket) </p><p>
37、 ?、莺瘮?shù)getIP:該函數(shù)實(shí)現(xiàn)從一個(gè)hashtable中根據(jù)value得到key的功能,函數(shù)原型如下:</p><p> public static String getIP(Hashtable ip2nickname,String nickname)</p><p> ?、藓瘮?shù)getNickname:該函數(shù)實(shí)現(xiàn)從socket和IP地址——昵稱對照hashtable中得到用戶的昵稱的功
38、能,函數(shù)原型如下:</p><p> public static String getNickname(Socket socket,Hashtable ip2nickname)</p><p> ?、吆瘮?shù)updateOnLineUsersList:該函數(shù)實(shí)現(xiàn)將在線用戶列表的顯示清空,并用最新的用戶列表更新客戶端的用戶列表,只顯示昵稱,函數(shù)原型如下:</p><p>
39、; public static void updateOnLineUsersList(List onLineUsersList,String allNickname)</p><p> ?、嗪瘮?shù)updateOnLineUsersList:該函數(shù)實(shí)現(xiàn)將在線用戶列表的顯示清空,并用最新的用戶列表更新服務(wù)器端的用戶列表:顯示的是ip:昵稱,函數(shù)原型如下:</p><p> public st
40、atic void updateOnLineUsersList(List onLineUsersList,Hashtable ip2nickname)</p><p> ?、岷瘮?shù)getSocketByIP:該函數(shù)實(shí)現(xiàn)根據(jù)用戶ip地址得到該用戶所在的socket功能,函數(shù)原型如下:</p><p> public static Socket getSocketByIP(ArrayList
41、onLineUsers,String ip)</p><p> ?、夂瘮?shù)getServiceByIP,該函數(shù)實(shí)現(xiàn)根據(jù)用戶ip地址得到該用戶所在的service功能,函數(shù)原型如下:</p><p> public static Service getServiceByIP(ArrayList allService,String ip)</p><p> 4.2客戶
42、端設(shè)計(jì)與編碼</p><p> 由于服務(wù)器端需要一次處理多個(gè)客戶端的請求,所以客戶端的設(shè)計(jì)均使用了Java的多線程處理機(jī)制實(shí)現(xiàn)。</p><p> 4.2.1客戶端程序</p><p> 該段功能由Client.java文件中的Client類實(shí)現(xiàn)(程序代碼請見附錄),具體實(shí)現(xiàn)過程如下:</p><p> ①新建客戶端:初始化該客戶端的
43、監(jiān)聽器、套接字、在線用戶列表以及發(fā)送消息的String流,并且將客戶端連接狀態(tài)設(shè)置為真。初始化一個(gè)客戶端時(shí),需要用到該客戶端的IP地址、端口號、在線用戶列表以及聊天內(nèi)容列表等信息。</p><p> ②建立監(jiān)聽:創(chuàng)建一個(gè)BufferedReader以及一個(gè)PrintStream之后,再通過多線程機(jī)制建立對服務(wù)器發(fā)來消息進(jìn)行監(jiān)聽的監(jiān)聽器Listener。</p><p> ?、郯l(fā)送消息:客
44、戶端循環(huán)發(fā)送消息給服務(wù)器,直到發(fā)送的String流遇到結(jié)尾字符。</p><p><b> 4.2.2文件發(fā)送</b></p><p> 該段功能主要實(shí)現(xiàn)文件發(fā)送,默認(rèn)端口為9900,由FileSender.java文件中的FileSender類實(shí)現(xiàn)(程序代碼請見附錄),具體實(shí)現(xiàn)過程如下:</p><p> ①初始化:使用接收端用戶的昵
45、稱、需要被傳輸?shù)奈募约傲奶煊涗浟斜沓跏蓟疐ileSender相應(yīng)的屬性。</p><p> ②用需要被傳輸?shù)奈募陆ㄒ粋€(gè)文件輸入流,通過該文件輸入流新建一個(gè)緩沖輸入流,用于緩沖文件輸入數(shù)據(jù);同時(shí)使用接收端用戶的IP地址以及端口號新建一個(gè)套接字,并通過該套接字建立一個(gè)緩沖輸出流,用于文件輸出數(shù)據(jù)的緩沖及刷新,然后使用一個(gè)字節(jié)數(shù)組用于讀取文件數(shù)據(jù)。</p><p> 初始化進(jìn)度條:
46、設(shè)置其最小值為零,最大值為文件長度除以字節(jié)數(shù)組長度。</p><p> ?、馨l(fā)送文件數(shù)據(jù):循環(huán)從字節(jié)數(shù)組中讀取數(shù)據(jù),若沒有到String流的結(jié)尾,則更新count值為原值與此時(shí)字節(jié)數(shù)組的長度之和,根據(jù)此時(shí)的count值修改進(jìn)度條的值,再將字節(jié)數(shù)組中的數(shù)據(jù)寫入到用于輸出的套接字中,并刷新輸出流。</p><p> ⑤關(guān)閉輸入輸出流以及建立的套接字,系統(tǒng)使用對話框提示用戶文件發(fā)送成功,再
47、次將進(jìn)度條設(shè)置為不可見,文件長度設(shè)置為零,以便下一次文件傳輸使用。 }</p><p><b> 4.2.3文件接收</b></p><p> 該段功能主要實(shí)現(xiàn)文件接收,默認(rèn)端口為9900,由FileReceiver.java文件中的FileReceiver類實(shí)現(xiàn)(程序代碼請見附錄),具體實(shí)現(xiàn)過程如下:</p><p>
48、; ?、俪跏蓟菏褂眯枰粋鬏?shù)奈募约傲奶煊涗浟斜沓跏蓟疐ileReciever相應(yīng)的屬性。</p><p> ?、谟眯枰粋鬏?shù)奈募陆ㄒ粋€(gè)文件輸出流,通過該文件輸入流新建一個(gè)緩沖輸出流,用于緩沖文件輸出數(shù)據(jù)及刷新;同時(shí)使用發(fā)送端用戶的端口號新建一個(gè)服務(wù)器套接字,并通過該套接字的accept()方法建立一個(gè)緩沖輸入流,用于文件輸入數(shù)據(jù)的緩沖,然后使用一個(gè)字節(jié)數(shù)組用于讀取文件數(shù)據(jù)。</p>
49、<p> ?、劢邮瘴募?shù)據(jù):循環(huán)從字節(jié)數(shù)組中讀取數(shù)據(jù),若沒有到String流的結(jié)尾,則更新count值為原值與此時(shí)字節(jié)數(shù)組的長度之和,根據(jù)此時(shí)的count值修改進(jìn)度條的值,再將字節(jié)數(shù)組中的數(shù)據(jù)寫入到用于輸出的文件中,并刷新輸出流。</p><p> ?、荜P(guān)閉輸入輸出流以及建立的套接字,系統(tǒng)使用對話框提示用戶接收文件成功,再次將進(jìn)度條設(shè)置為不可見,文件長度設(shè)置為零,以便下一次文件傳輸使用。 <
50、;/p><p><b> 4.2.4消息監(jiān)聽</b></p><p> 該類主要實(shí)現(xiàn)對服務(wù)器發(fā)送的消息進(jìn)行監(jiān)聽的功能,由Listener.java文件中的Listener類實(shí)現(xiàn)(程序代碼請見附錄),具體實(shí)現(xiàn)過程如下:</p><p> ①使用緩沖輸入流、在線用戶列表以及聊天記錄列表初始化Listener對象的相關(guān)屬性,并啟動(dòng)多線程。<
51、/p><p> ②循環(huán)接收從服務(wù)器發(fā)送來的信息,直到輸入流讀到了String流的末尾,接著開始判斷消息的類型。</p><p> ?、廴艨刂谱忠浴癗ICKNAME”開始,則證明需要更新用戶列表,此時(shí)客戶端進(jìn)行相關(guān)操作。</p><p> ?、苋缈刂谱忠浴癋ILEECFO”開始,則客戶端需要通過控制字以后的字符獲得目的端的IP地址。</p><
52、p> ⑤若控制字以“FLENGHTH”開頭,則客戶端可以獲得需要傳輸?shù)奈募L度。</p><p> ?、奕艨刂谱侄疾粷M足②—⑤的條件,則將該信息作為是交談內(nèi)容更新在聊天記錄列表中。</p><p><b> 4.3運(yùn)行結(jié)果</b></p><p> 4.3.1服務(wù)器啟動(dòng)服務(wù)</p><p> 4.3.2
53、客戶端登陸</p><p> 4.3.3服務(wù)器實(shí)現(xiàn)其管理功能</p><p> ?、傧蛩锌蛻舳税l(fā)送消息</p><p> 向某一個(gè)客戶端發(fā)送消息</p><p> 制修改某個(gè)客戶端的昵稱</p><p> 4.3.4客戶端向所有客戶端廣播</p><p> 4.3.5客戶端與客戶端間
54、實(shí)現(xiàn)“私聊”</p><p> 4.3.6客戶端與客戶端之間實(shí)現(xiàn)文件傳輸功能</p><p><b> ?、傥募l(fā)送</b></p><p><b> ②文件接收</b></p><p><b> 文件傳輸過程中</b></p><p><b
55、> 傳輸完成</b></p><p><b> 用戶離開</b></p><p><b> 服務(wù)器關(guān)閉</b></p><p><b> Ⅴ結(jié)論與總結(jié)</b></p><p><b> 5.1課程設(shè)計(jì)結(jié)論</b></p&g
56、t;<p> 通過4.3運(yùn)行結(jié)果,可以看出,該課程設(shè)計(jì)利用Java應(yīng)用程序Socket編程實(shí)現(xiàn)了以下功能:使用Java的多線程處理機(jī)制建立兩個(gè)套接字分別作為服務(wù)器端和客戶端。</p><p> 在服務(wù)器端實(shí)現(xiàn)了向各個(gè)客戶端發(fā)布系統(tǒng)消息,接受來自客戶端的各種信息并分別處理的功能,可以控制客戶端的連接以及對用戶的管理作用,并且能夠適時(shí)檢測已登錄用戶的連接狀態(tài)且刷新在線用戶列表,更能夠解析客戶端與服務(wù)
57、器端的消息交互并做出相應(yīng)處理。</p><p> 在客戶端實(shí)現(xiàn)了向服務(wù)器端發(fā)布消息,并且對來自服務(wù)器的消息做出相應(yīng)的響應(yīng),可以連接到特定的服務(wù)器,設(shè)置自己的昵稱,并且能夠監(jiān)聽服務(wù)器端發(fā)送過來的消息并做出相應(yīng)的響應(yīng),更加能夠與其他用戶進(jìn)行廣播或私聊,以及實(shí)現(xiàn)文件傳輸?shù)裙δ堋?lt;/p><p> 由此,可見,本次課程設(shè)計(jì)完成了最初的設(shè)計(jì)要求,即實(shí)現(xiàn)了類似P2P的QQ聊天系統(tǒng),有相應(yīng)的客戶端和
58、服務(wù)器端;服務(wù)器端可以記錄當(dāng)前在線客戶列表,把客戶列表發(fā)送給每一個(gè)在線客戶,并實(shí)時(shí)刷新;任何一個(gè)用戶都可以和任意其它的用戶進(jìn)行交互,即從在線客戶列表中選擇一個(gè)或一組其它用戶通過服務(wù)器的轉(zhuǎn)發(fā)彼此進(jìn)行信息的交互以及文件的交互。</p><p> 5.2課程設(shè)計(jì)總結(jié)與體會(huì)</p><p> 在本次課程設(shè)計(jì)中,我們綜合應(yīng)用所學(xué)過的知識,在使用Java應(yīng)用程序的Socket編程機(jī)制的基礎(chǔ)上,根據(jù)
59、傳輸層的傳輸控制協(xié)議TCP協(xié)議的原理,設(shè)計(jì)點(diǎn)對點(diǎn)數(shù)據(jù)交換程序,并且實(shí)現(xiàn)服務(wù)器端和客戶端的主要功能。另外,根據(jù)自己編寫的程序,成功地實(shí)現(xiàn)了用戶之間的聊天及文件傳輸功能,這一次的課程設(shè)計(jì),使我們掌握了網(wǎng)絡(luò)傳輸數(shù)據(jù)的概念、原理以及設(shè)計(jì)方法,也加深了對傳輸控制協(xié)議TCP的理解。通過本次課程設(shè)計(jì),我們清楚地了解到TCP、UDP協(xié)議的原理及二者的區(qū)別,學(xué)會(huì)了網(wǎng)絡(luò)中數(shù)據(jù)傳輸?shù)幕靖拍?、基本原理和設(shè)計(jì)步驟、設(shè)計(jì)思路和調(diào)試步驟,體會(huì)到了程序設(shè)計(jì)結(jié)構(gòu)在整個(gè)
60、設(shè)計(jì)中起到的重要作用,最終能夠清晰地解析計(jì)算機(jī)網(wǎng)絡(luò)中數(shù)據(jù)傳輸這一概念,為進(jìn)一步的網(wǎng)絡(luò)知識學(xué)習(xí)奠定了基礎(chǔ),并且完成對《計(jì)算機(jī)網(wǎng)絡(luò)》這門課程的綜合應(yīng)用,真正體現(xiàn)了“學(xué)以致用”的機(jī)制。</p><p> 本次課程設(shè)計(jì)中,因?yàn)橛欣蠋煹男燎谥笇?dǎo),我們設(shè)計(jì)小組對理論知識進(jìn)行了充分研究,發(fā)揚(yáng)了創(chuàng)新實(shí)踐精神,積極探索,努力勤勉,共同越過了設(shè)計(jì)路上的每一處障礙,攻克了一個(gè)又一個(gè)的難關(guān)。最終,友好的協(xié)作關(guān)系與團(tuán)隊(duì)凝聚力促使我們順利
61、地完成了此次課程設(shè)計(jì)。</p><p> 本次課程設(shè)計(jì),加深了我們對理論知識的理解,也鍛煉了我們的實(shí)踐能力,更多的是在實(shí)踐中收獲了太多的感觸和心得,.雖然計(jì)算機(jī)組成原理的課程設(shè)計(jì)已經(jīng)結(jié)束,可我們明白“學(xué)無止境”的道理,我們會(huì)繼續(xù)刻苦鉆研,求實(shí)創(chuàng)新,不斷地用知識來充實(shí)自己,跟上科技時(shí)代前進(jìn)的步伐。</p><p> 在此次的設(shè)計(jì)中,非常感謝老師對我們的幫助和指導(dǎo)。才疏學(xué)淺,過程難免還不夠
62、完善,望老師再次不吝賜教!</p><p> ?、?課程設(shè)計(jì)分工及參考文獻(xiàn)</p><p><b> 6.1課程設(shè)計(jì)分工</b></p><p> 劉龍:服務(wù)器端程序的設(shè)計(jì)以及實(shí)現(xiàn),包括服務(wù)器端的連接控制、管理作用、刷新列表以及消息處理等功能的實(shí)現(xiàn):服務(wù)器端界面的設(shè)計(jì)和窗口事件的處理,實(shí)現(xiàn)服務(wù)器端和客戶端的的登錄信息、聊天記錄功能的實(shí)現(xiàn)
63、.</p><p> 奉光陽:客戶端界面的設(shè)計(jì)和窗口事件的處理,以及實(shí)現(xiàn)客戶端的連接功能、登錄設(shè)計(jì)以及,提出消息處理的基本模式,以及客戶端消息處理功能的實(shí)現(xiàn),實(shí)現(xiàn)客戶端和服務(wù)器端的登錄信息、聊天記錄功能的實(shí)現(xiàn).</p><p><b> 。 </b></p><p> 韓超: 點(diǎn)對點(diǎn)信息交互的實(shí)現(xiàn),監(jiān)聽功能,文件傳輸進(jìn)度條的開發(fā)與
64、實(shí)現(xiàn),搜集資料,文件傳輸機(jī)制的設(shè)計(jì)與實(shí)現(xiàn),同時(shí)對進(jìn)度條和文件保存功能的實(shí)現(xiàn)。課程設(shè)計(jì)報(bào)告資料的搜集與整理,補(bǔ)充及修改課程設(shè)計(jì)報(bào)告</p><p> 體現(xiàn)了作為一個(gè)團(tuán)隊(duì)?wèi)?yīng)有的凝聚力,完成了本次課程設(shè)計(jì)。</p><p><b> 6.2參考文獻(xiàn)</b></p><p> [1]《計(jì)算機(jī)網(wǎng)絡(luò)》第4版 謝希仁 電子工業(yè)出版社 2003年6
65、月</p><p> [2]《用TCP/IP進(jìn)行網(wǎng)絡(luò)互聯(lián)》(第一卷) D.E.Comer 電子工業(yè)出版社2004年11月第四版</p><p> [3]《TCP/IP網(wǎng)絡(luò)原理與技術(shù)》周明天、汪文勇清華大學(xué)出版社:1993</p><p> [4《Java程序設(shè)計(jì)之網(wǎng)絡(luò)編程》李芝興、楊瑞龍、朱慶生 清華大學(xué)出版社 2006年3月第一版 <
66、;/p><p><b> ?、鞲戒?</b></p><p> 實(shí)現(xiàn)代碼(內(nèi)容已被演說,僅附關(guān)鍵性代碼)</p><p> 7.1.1 服務(wù)器程序</p><p> //Server.java</p><p> 在服務(wù)器端維護(hù)一個(gè)hashtable,用來存放各客戶端的IP地址與用戶昵稱之間的對
67、照關(guān)系映射。</p><p> Hashtable ip2nickname=new Hashtable();</p><p> ArrayList allService=new ArrayList();</p><p> String clientIP=client.getInetAddress().getHostAddress();</p>&
68、lt;p> //判斷該客戶端已經(jīng)連接的話,提示退出</p><p> if(ip2nickname.get(clientIP)!=null)</p><p><b> {</b></p><p> ChatTookit.sendInfo(client,"已經(jīng)有客戶端從該ip地址連接服務(wù)器,本次連接將退出!");
69、</p><p><b> break;</b></p><p><b> }</b></p><p> //把新建連接的用戶加入當(dāng)前用戶列表</p><p> onLineUsers.add(client);</p><p> //默認(rèn)情況下,即在還沒有收到用戶自
70、定義昵稱的清空下,把用戶的IP地址做為其昵稱維護(hù)入ip2nickname</p><p> ip2nickname.put(clientIP,clientIP);</p><p> //在服務(wù)器端提示有新的客戶連接</p><p> this.onLineUsersList.add(clientIP);</p><p> this.c
71、hatContentList.add(clientIP+" 來了");</p><p> //對所有已連接的客戶端,發(fā)送兩條信息,1提示有新用戶連接,2最新在線用戶昵稱列表</p><p> ChatTookit.sendInfoToAll(onLineUsers,ChatTookit.getAllNickname(ip2nickname));</p>
72、<p> ChatTookit.sendInfoToAll(onLineUsers,clientIP+" 來了");</p><p> //針對每個(gè)client連接啟動(dòng)其特定服務(wù)線程</p><p> Service(client,ip2nickname,onLineUsersList,chatContentList,onLineUsers,chatC
73、ontent);</p><p> this.allService.add(service);;</p><p> } catch (IOException ex) </p><p><b> {</b></p><p> JOptionPane.showMessageDialog(null,"接收客戶
74、端連接時(shí)出現(xiàn)問題!", "提示",JOptionPane.INFORMATION_MESSAGE);</p><p><b> }</b></p><p><b> }</b></p><p><b> }</b></p><p> //強(qiáng)
75、制更改用戶的昵稱</p><p> public void changeNickname(String oldName,String newName)</p><p><b> {</b></p><p> //如果該昵稱已經(jīng)被別人使用則不進(jìn)行更改</p><p> if(ip2nickname.contains
76、(newName))</p><p><b> {</b></p><p> chatContent.add("該昵稱已經(jīng)有人使用,所以不做任何更改");</p><p> this.chatContentList.select(this.chatContentList.getItemCount()-1);</p
77、><p><b> return;</b></p><p><b> }</b></p><p> //找到舊昵稱所在的ip地址</p><p> String ip=ChatTookit.getIP(ip2nickname,oldName);</p><p> //用
78、新昵稱更新舊昵稱</p><p> ip2nickname.put(ip,newName);</p><p> //將負(fù)責(zé)該用戶的Service里的昵稱變量進(jìn)行修改</p><p> Service service=ChatTookit.getServiceByIP(allService,ip);</p><p> service.c
79、hangeNickname(newName);</p><p> //刷新服務(wù)器端的顯示</p><p> chatContentList.add("系統(tǒng)管理員 將 "+oldName+" 的昵稱改為 "+newName);</p><p> this.chatContentList.select(this.chatCo
80、ntentList.getItemCount()-1);</p><p> ChatTookit.updateOnLineUsersList(onLineUsersList,ip2nickname);</p><p> //刷新各客戶端的顯示</p><p> //先給該客戶端提供提示信息</p><p> ChatTookit.se
81、ndInfo(client,"你已經(jīng)被系統(tǒng)管理員踢出聊天室");</p><p> client.close();</p><p><b> } </b></p><p> catch (IOException ex) </p><p><b> {</b></p&
82、gt;<p> JOptionPane.showMessageDialog(null, "關(guān)閉客戶端"+ip+"時(shí)出錯(cuò)!", "提示",JOptionPane.INFORMATION_MESSAGE);</p><p><b> }</b></p><p> //刷新服務(wù)器端的顯示<
83、/p><p> chatContentList.add("系統(tǒng)管理員 將 "+nickname+" 踢出聊天室!");</p><p> this.chatContentList.select(this.chatContentList.getItemCount()-1);</p><p> ChatTookit.update
84、OnLineUsersList(onLineUsersList,ip2nickname);</p><p> //刷新各客戶端的顯示</p><p><b> try </b></p><p><b> {</b></p><p> ChatTookit.sendInfoToAll(onLi
85、neUsers,"系統(tǒng)管理員 將 " +nickname+" 踢出聊天室!");</p><p> ChatTookit.sendInfoToAll(onLineUsers,ChatTookit.getAllNickname(ip2nickname));</p><p><b> } </b></p><
86、p> catch (IOException ex) </p><p><b> {</b></p><p> JOptionPane.showMessageDialog(null, "發(fā)送信息出錯(cuò)!", "提示",JOptionPane.INFORMATION_MESSAGE);</p><p&g
87、t;<b> }</b></p><p><b> }</b></p><p><b> }</b></p><p><b> 7.1.3功能函數(shù)</b></p><p> public class ChatTookit {</p>
88、<p> //從IP地址——昵稱對照hashtabel中得到所有的昵稱</p><p> public static String getAllNickname(Hashtable ip2nickname){</p><p> String allNickname="NICKNAME:";</p><p> Enumerati
89、on e=ip2nickname.elements();</p><p> while(e.hasMoreElements()){</p><p> allNickname+=(String)e.nextElement()+" ";</p><p><b> }</b></p><p> re
90、turn allNickname;</p><p><b> }</b></p><p> //遍歷所有已連接的客戶端,發(fā)送輸入的信息</p><p> public static void sendInfoToAll(ArrayList onLineUsers,String info) throws</p><p&g
91、t; IOException {</p><p> for (int i = 0; i < onLineUsers.size(); i++) {</p><p> Socket c = (Socket) onLineUsers.get(i);</p><p> PrintStream ps = new PrintStream(c.getOutputSt
92、ream());</p><p> ps.println(info);</p><p><b> }</b></p><p><b> }</b></p><p> //給某個(gè)特定用戶發(fā)送一條信息</p><p> public static void sendIn
93、fo(Socket client,String info) throws IOException {</p><p> PrintStream ps = new PrintStream(client.getOutputStream());</p><p> ps.println(info);</p><p><b> }</b></
94、p><p> //從socket中得到用戶的ip地址</p><p> public static String getIP(Socket socket){</p><p> return socket.getInetAddress().getHostAddress();</p><p><b> }</b><
95、/p><p> //從socket和IP地址——昵稱對照hashtable中得到用戶的昵稱</p><p> public static String getNickname(Socket socket,Hashtable ip2nickname){</p><p> return (String)ip2nickname.get(getIP(socket));&l
96、t;/p><p><b> }</b></p><p> //將在線用戶列表的顯示清空,并用最新的用戶列表更新</p><p> //客戶端的:第二個(gè)參數(shù)是字符串,只顯示昵稱</p><p> public static void updateOnLineUsersList(List onLineUsersList,
97、String allNickname){</p><p> onLineUsersList.removeAll();</p><p> StringTokenizer st = new StringTokenizer(allNickname);</p><p> while (st.hasMoreTokens()) {</p><p>
98、 onLineUsersList.add(st.nextToken());</p><p><b> }</b></p><p><b> }</b></p><p> //服務(wù)器端的:第二個(gè)參數(shù)是hashtable,顯示的是ip:昵稱</p><p> public static voi
99、d updateOnLineUsersList(List onLineUsersList,Hashtable ip2nickname){</p><p> onLineUsersList.removeAll();</p><p> Enumeration e=ip2nickname.keys();</p><p> while(e.hasMoreElement
100、s()){</p><p> String ip=(String)e.nextElement();</p><p> onLineUsersList.add((String)ip2nickname.get(ip)+"@"+ip);</p><p><b> }</b></p><p><b
101、> }</b></p><p> //根據(jù)用戶ip地址得到該用戶所在的socket</p><p> public static Socket getSocketByIP(ArrayList onLineUsers,String ip){</p><p> Socket client=null;</p><p>
102、for(int i=0;i<onLineUsers.size();i++){</p><p> client=(Socket)onLineUsers.get(i);</p><p> if(getIP(client).equals(ip)){</p><p><b> break;</b></p><p>&
103、lt;b> }</b></p><p><b> }</b></p><p> return client;</p><p><b> }</b></p><p> //根據(jù)用戶ip地址得到該用戶所在的service</p><p> Servi
104、ce service=null;</p><p> for(int i=0;i<allService.size();i++){</p><p> service=(Service)allService.get(i);</p><p> if(service.getIP().equals(ip)){</p><p><b>
105、; break;</b></p><p><b> 7.1.4信息處理</b></p><p> //Service.java</p><p> //接收信息,將用戶發(fā)過來的信息顯示在服務(wù)器端面板上,并遍歷發(fā)送給所有的客戶端。</p><p> while((word=br.readLine())!
106、=null)</p><p><b> {</b></p><p> //判斷是否是修改昵稱</p><p> if(word.startsWith("NICKNAME:"))</p><p><b> {</b></p><p> word=w
107、ord.substring(9);</p><p> //如果用戶的昵稱已經(jīng)被別的用戶使用,提示用戶重新起昵稱</p><p> if(ip2nickname.contains(word))</p><p><b> {</b></p><p> ChatTookit.sendInfo(client,"
108、系統(tǒng)管理員:該昵稱已存在,請重新起新的昵稱!");</p><p><b> continue;</b></p><p><b> }</b></p><p> this.ip2nickname.put(clientIP,word);</p><p> //更新服務(wù)器端的顯示<
109、;/p><p> this.chatContentList.add(this.nickname+" 將昵稱改為 "+word);</p><p> ChatTookit.updateOnLineUsersList(onLineUsersList,ip2nickname);</p><p> //將更新信息發(fā)送給所有客戶端</p>
110、<p> ChatTookit.sendInfoToAll(onLineUsers,this.nickname+" 將昵稱改為 "+word);</p><p> ChatTookit.sendInfoToAll(onLineUsers,ChatTookit.getAllNickname(this.ip2nickname));</p><p> this
111、.nickname=word;</p><p><b> }</b></p><p> else if(word.startsWith("FLENGTH:"))</p><p><b> {</b></p><p> word=word.substring(8);<
112、/p><p> String toNickname=word.substring(0,word.indexOf("$SPECIAL$"));</p><p> word=word.substring(word.indexOf("$SPECIAL$")+9);</p><p> Socket client=ChatTookit
113、.getSocketByIP(onLineUsers,ChatTookit.getIP(ip2nickname,toNickname));</p><p> ChatTookit.sendInfo(client,"FLENGTH:"+word);</p><p><b> }</b></p><p> //是否是只發(fā)送
114、給特定用戶</p><p> else if(word.startsWith("SPECIAL:"))</p><p><b> {</b></p><p> word=word.substring(8);</p><p> String toNickname=word.substring(0
115、,word.indexOf("$SPECIAL$"));</p><p> word=word.substring(word.indexOf("$SPECIAL$")+9);</p><p> //根據(jù)昵稱找到該客戶端</p><p> Socket client=ChatTookit.getSocketByIP(onL
116、ineUsers,ChatTookit.getIP(ip2nickname,toNickname));</p><p> ChatTookit.sendInfo(client,this.nickname+" 悄悄對你說:"+word);</p><p> this.chatContent.add(this.nickname+" 對 "+toNic
117、kname+" 悄悄的說:"+word);</p><p><b> }</b></p><p> //是否是想對某個(gè)用戶發(fā)送文件</p><p> else if(word.startsWith("FILE:"))</p><p><b> {</b>
118、;</p><p> word=word.substring(5);</p><p> String toNickname=word.substring(0,word.indexOf("$FILE$"));</p><p> word=word.substring(word.indexOf("$FILE$")+6);&l
119、t;/p><p> //根據(jù)昵稱找到該客戶端</p><p> clientD=ChatTookit.getSocketByIP(onLineUsers,ChatTookit.getIP(ip2nickname,toNickname));</p><p> ChatTookit.sendInfo(clientD,this.nickname+" 想發(fā)送文件
120、 "+word+" 給你,請點(diǎn)“保存”按鈕選擇要保存的位置,再點(diǎn)“開始”按鈕開始接收文件");</p><p> //將目標(biāo)用戶的ip地址發(fā)送給原用戶</p><p> ChatTookit.sendInfo(this.client,"FILEECHO:"+clientD.getInetAddress().getHostAddress(
121、));</p><p> this.chatContent.add(this.nickname+" 想給 "+toNickname+" 發(fā)送文件 "+word);</p><p><b> }</b></p><p><b> //文件傳輸完畢</b></p>&
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 眾賞文庫僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)--聊天室
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)報(bào)告 (2)
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)報(bào)告
- 《計(jì)算機(jī)網(wǎng)絡(luò)》課程設(shè)計(jì)報(bào)告
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)報(bào)告
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)報(bào)告
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)報(bào)告
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)報(bào)告
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)報(bào)告
- 《計(jì)算機(jī)網(wǎng)絡(luò)》課程設(shè)計(jì)報(bào)告
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)報(bào)告
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)報(bào)告
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì) (2)
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì) (2)
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)
- 《計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)》
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)
- 計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)
評論
0/150
提交評論