

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、<p><b> 目錄</b></p><p> ?、裥枨蠓治?……………………………………………………………………………5</p><p> 1.1課程設計目的 ……………………………………………………………………5</p><p> 1.2課程設計要求 ……………………………………………………………………5</p&g
2、t;<p> 1.3選題與操作流程 …………………………………………………………………5</p><p> 1.4開發(fā)環(huán)境與開發(fā)平臺 ……………………………………………………………5</p><p> ?、蚩傮w設計 ……………………………………………………………………………5</p><p> 2.1總體設計概念 ……………………………………
3、………………………………5</p><p> 2.2系統(tǒng)功能 …………………………………………………………………………5</p><p> 2.3系統(tǒng)架構 …………………………………………………………………………6</p><p> 2.4 模塊劃分 …………………………………………………………………………6</p><p> ?、?/p>
4、詳細設計 ……………………………………………………………………………6</p><p> 3.1軟件層次模型 ……………………………………………………………………6</p><p> 3.2協(xié)議結構 …………………………………………………………………………6</p><p> 3.3數(shù)據(jù)流程圖 ………………………………………………………………………8&
5、lt;/p><p> Ⅳ系統(tǒng)實現(xiàn)編碼及運行結果 …………………………………………………………9</p><p> 4.1服務器端設計與編碼 ……………………………………………………………9</p><p> 4.2客戶端設計與編碼 ………………………………………………………………11</p><p> 4.3運行結果 ………………
6、…………………………………………………………12</p><p> ?、踅Y論與總結 …………………………………………………………………………19</p><p> 5.1課程設計結論 …………………………………………………………………… 20</p><p> 5.2課程設計總結與體會 ……………………………………………………………20</p>
7、<p> ?、稣n程設計分工及參考文獻 …………………………………………………………20</p><p> 6.1課程設計分工 ……………………………………………………………………20</p><p> 6.2參考文獻 …………………………………………………………………………21</p><p> ?、鞲戒?………………………………………………………
8、………………………22</p><p> 關鍵代碼……………………………………………………………………… 22</p><p><b> Ⅰ 需求分析</b></p><p><b> 1.1課程設計目的</b></p><p> 本次計算機網絡課程設計,旨在通過該課程設計,使學生了解、掌握
9、TCP、UDP協(xié)議的原理;了解、掌握Socket編程的方法;了解、掌握應用協(xié)議設計的思想;利用Winsock API或者Java Socket API編制一個能部署在Internet上的點對點數(shù)據(jù)交換(P2P)、HTTP/FTP服務器系統(tǒng)、共享白板。</p><p><b> 1.2課程設計要求</b></p><p> 要求每組學生從上述3個系統(tǒng)中任選一個,獨立
10、完成系統(tǒng)的功能設計和實現(xiàn),使所實現(xiàn)的系統(tǒng)可以能夠包含主要的內容要求,并要求學生必須在報告中明確具體分工情況。</p><p> 1.3選題與操作流程</p><p> 在網絡越來越發(fā)達的今天,人們對網絡的依賴越來越多,越來越離不開網絡,由此而產生的聊天工具越來越多,類似QQ、網絡聊天時一類的聊天系統(tǒng)的發(fā)展日新月異。因此,基于我們實際的知識結構構成以及網絡聊天在當今時代的盛行趨勢,本課程
11、設計小組選擇了課程設計題目點對點數(shù)據(jù)交換(P2P),用于實現(xiàn)基于服務器轉發(fā)的任意多點間的數(shù)據(jù)共享與交換。其具體設計內容如下:</p><p> 1)類似P2P的QQ聊天系統(tǒng),有客戶端和服務器端。</p><p> 2)服務器端記錄當前在線客戶列表,把客戶列表發(fā)送給每一個在線客戶,并實時刷新。</p><p> 3)任一個客戶可以和任意其它的客戶進行交互,即從在
12、線客戶列表中選擇一個或一組其它客戶通過服務器轉發(fā)彼此進行交互,包括信息交互,文件交互。</p><p><b> Ⅱ總體設計</b></p><p><b> 2.1總體設計概念</b></p><p> 為實現(xiàn)網絡聊天的功能,采用Java Socket編程,服務器與客戶端采用了TCP/IP連接方式,在設計聊天方案時
13、,實行將所有信息發(fā)往服務器端,再由服務器進行分別處理的思路,服務器端是所有信息的中心。</p><p> 服務器端可以查看所有用戶的聊天記錄,監(jiān)控所有用戶的狀態(tài),發(fā)出用戶上線提示等公告,客戶端則提供接收公告的功能。</p><p><b> 2.2系統(tǒng)功能</b></p><p> 本課程設計按照實驗的具體要求,首先應用Socket編程創(chuàng)
14、建客戶端和服務器端,它們之間通過一個交互的連接來實現(xiàn)數(shù)據(jù)通信;然后在客戶端 設置一個監(jiān)聽器,用于監(jiān)聽服務器發(fā)來的消息;最后在客戶端設置點對點的文件交互需要用到的接受和發(fā)送類,以及表征文件傳輸過程的進度條。</p><p><b> 2.3系統(tǒng)架構</b></p><p> 1)選擇傳輸控制協(xié)議TCP,使用Java的Socket編程機制,分別建立客戶端與服務器端;&
15、lt;/p><p> 2)分別設計客戶端與服務器端的界面,并使用Java應用程序用戶界面的開發(fā)工具包Swing進行窗體界面的布局,以及實現(xiàn)部分窗口事件的相應。</p><p><b> 2.4 模塊劃分</b></p><p> 1)服務器端,主要實現(xiàn)向各個客戶端發(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)客戶端:主要實現(xiàn)向服務器端發(fā)布消息,并且對來自服務器的消息做出相應的響應。具體功能如下:</p><p><b> ①連接功能:</b></p><p><b> ?、诘卿浽O
18、置:</b></p><p><b> ?、郾O(jiān)聽作用:</b></p><p><b> ?、芟⑻幚恚?lt;/b></p><p><b> ?、萘奶煊涗洠?lt;/b></p><p><b> ⑥消息處理:</b></p>
19、<p><b> ?、邆鬏斶M度:</b></p><p><b> ⑧文件傳輸:</b></p><p><b> ?、?詳細設計</b></p><p><b> 3.1軟件層次模型</b></p><p> 服務器層次結構和客戶端
20、層次結構。</p><p><b> 3.2協(xié)議結構</b></p><p> 在Java socket通信中使用的協(xié)議是TCP協(xié)議。TCP協(xié)議是TCP/IP協(xié)議中面向連接的運輸層協(xié)議,它提供全雙工的和可靠交付的服務。由于通信是全雙工方式,因此TCP連接的任何一方都能夠發(fā)送和接收數(shù)據(jù)。發(fā)送端的應用進程按照自己產生數(shù)據(jù)的規(guī)律,不斷地將數(shù)據(jù)塊(其長短可能各異)陸續(xù)寫入
21、到TCP的發(fā)送緩存中。TCP再從發(fā)送緩存中取出一定數(shù)量的數(shù)據(jù),將其組成TCP報文段逐個傳給IP層,然后發(fā)送出去。接收端從IP層收到TCP報文段后,先將其存在接收緩存中,然后讓接收端的進程從接收緩存中將數(shù)據(jù)塊逐個讀取。 </p><p> TCP協(xié)議的報文分為首部和數(shù)據(jù)兩個部分。眾所周知首部中含有源端口、目的端口、序號、確認號等內容。因此在利用socket通信時,要想實現(xiàn)不同的功能和數(shù)據(jù)傳輸,包括指令和純數(shù)據(jù)的傳
22、輸,可以通過在TCP報文的數(shù)據(jù)部分進行再分段來實現(xiàn)。由此指定一些套接字,并接利用這些套接字來對不同的數(shù)據(jù)進行分段,這樣就能輕松地將提取所需數(shù)據(jù)以實現(xiàn)不同功能。</p><p> 本課程設計正是利用上述方法來建立一個基于TCP協(xié)議的協(xié)議。這個協(xié)議的主要組成部分為套接字及數(shù)據(jù)段。在程序中主要使用的套接字有:“NICKNAME:”、“SPECIAL:”、“$SPECIAL$”、“FLENGTH:”、“FILEECHO
23、:”以及“FILE:”等。其中各個套接字又有不同的使用方法。</p><p> 如果數(shù)據(jù)沒有使用套接字,則就被默認為這一數(shù)據(jù)是廣播數(shù)據(jù)及聊天室的公開數(shù)據(jù),這樣的數(shù)據(jù)將會全部傳給聊天室里的各個用戶并且會保存在聊天室服務器里。</p><p> 如果使用的是“NICKNAME:”,則其后數(shù)據(jù)為發(fā)此數(shù)據(jù)者所要變更的昵稱。</p><p> 另外,將“$SPECIAL
24、$”當作劃分兩個數(shù)據(jù)的套接字,通常在一個套接字之后有兩種數(shù)據(jù)的情況下使用。</p><p> 如果使用的是“SPECIAL:”,則其后數(shù)據(jù)至“$SPECIAL$”之間的為目的昵稱,而在“$SPECIAL$”之后的則為所要傳輸?shù)男畔?shù)據(jù),同時我們擬定這個套接字為私聊套接字,雖通過服務器轉發(fā)但其內容不會在服務器上顯示。</p><p> 若套接字為“FILE:”,則表示該用戶發(fā)出了一個對一
25、的客戶文件傳送請求,此時,服務器端同樣通過控制字頭后的昵稱,查找到對應的接收端用戶的信息,并將該用戶的IP地址傳遞給發(fā)送端,并在服務器端顯示發(fā)送端想要對接收端傳輸文件的信息。協(xié)議格式如下:“FILE:”+目的昵稱+“$FILE$”+文件名稱。</p><p> 若套接字為“FILEFINISH:”,則表示客戶之間文件傳輸完畢,此時服務器端發(fā)出文件傳輸完畢的信息。</p><p> “F
26、LENGTH:”的套接字表示文件長度,其格式為“FLENGTH:”+目的昵稱+“$SPECIAL$”+文件長度。這樣我們在文件傳輸過程中就可以知道所接收文件的大小同時有益于進度條的使用。</p><p> 套接字“FILEECHO:”是為服務器發(fā)給客戶端的目的地的IP地址。</p><p> 使用套接字的方法能夠把控制信息和數(shù)據(jù)部分一起傳送達到服務器和客戶端的不同溝通,這樣我們就可以利
27、用服務器來完成我們所需的各個服務,無論公開聊天還是私下聊天都可以,同時還能在某種意義上保護隱私。這個socket的協(xié)議就是利用TCP協(xié)議的數(shù)據(jù)流、面向連接和全雙通來實現(xiàn)的。</p><p><b> 3.3數(shù)據(jù)流程圖</b></p><p> 根據(jù)以上的程序模塊劃分,設計好服務器端和客戶端的流程圖,如下:</p><p><b>
28、 ?、俜掌鞫肆鞒蹋?lt;/b></p><p><b> ②客戶端流程圖:</b></p><p> ?、?系統(tǒng)實現(xiàn)編碼及運行結果</p><p> 4.1服務器端設計與編碼</p><p> 4.1.1 服務器程序</p><p> 該段功能由Server.java文件中的Se
29、rver類實現(xiàn)(程序代碼請見附錄),具體實現(xiàn)過程如下:</p><p> ?、賳臃詹⒔邮者B接:服務器的任務首先是建立一個由IP地址到昵稱的映射的哈希表,用于存放用戶的基本信息;啟動服務器后,等候建立一個連接,然后用這個連接產生的Socket創(chuàng)建一個Client,同時檢查該用戶是否已存在哈希表中,若以存在,則提示該次連接請求失敗,從而實現(xiàn)限制IP的目的;若不存在,則將該IP地址及其昵稱或默認昵稱的映射添加到哈希
30、表中,接著服務器端向所有的用戶發(fā)送管理信息,提示有新的用戶登錄,并且將刷新后的用戶列表同時發(fā)送到各個客戶端。</p><p> ?、陉P閉服務:服務器端遍歷哈希表,關掉每一個用戶對應的Socket,之后,關閉服務Server。</p><p> ?、酃芾碜饔弥l(fā)送消息: 服務器端解析由客戶端發(fā)送的請求,若控制字以“SPECIAL”開頭,則通過控制字后的昵稱從哈希表中找到對應的用戶,實現(xiàn)服務器
31、端到客戶端的點對點消息交互;若不是以“SPECIAL”開頭,則實現(xiàn)消息的廣播發(fā)布。</p><p> ④管理作用之修改昵稱:首先判斷新的昵稱是否在哈希表中存在,若已存在則給出錯誤提示,否則通過該用戶的舊昵稱在哈希表中查找到該用戶,并用欲修改的昵稱替換掉原昵稱;接著刷新服務器端的用戶列表顯示,最后刷新客戶端的用戶列表顯示。</p><p> ?、莨芾碜饔弥當嚅_連接:若要斷開某個客戶端與服務
32、器的連接,首先向該用戶發(fā)送被管理員請出系統(tǒng)的信息,然后通過該用戶的昵稱從哈希表中找到對應socket、service及IP地址等信息,再從每一項信息對應的列表里刪除該用戶的信息,最后關閉該用戶的socket,同時刷新服務器端以及各個客戶端的用戶列表顯示。</p><p> ?、拊诜掌渲?,需要同時處理多個客戶端的請求,因此此處用到了多線程處理機制。在服務器程序里創(chuàng)建單個Server Socket,并調用accep
33、t()來等候一個新連接,一旦accept()返回,就取得結果獲得的socket,并用它新建一個線程,令其只為那個特定的客戶端服務,然后再調用accept(),等候下一次新的連接請求。</p><p><b> 4.1.2功能函數(shù)</b></p><p> 該段功能由ChatTookit.java文件中的ChatTookit類實現(xiàn)(程序代碼請見附錄),具體實現(xiàn)過程如
34、下:</p><p> ?、俸瘮?shù)getAllNickname:該函數(shù)實現(xiàn)從IP地址——昵稱對照哈希表中得到所有的昵稱的功能,函數(shù)原型如下:</p><p> public static String getAllNickname(Hashtable ip2nickname)</p><p> ?、诤瘮?shù)sendInfoToAll:該函數(shù)實現(xiàn)遍歷所有已連接的客戶端,并
35、且發(fā)送輸入的信息的功能,函數(shù)原型如下:</p><p> public static void sendInfoToAll(ArrayList onLineUsers,String info) throws IOException</p><p> ③函數(shù)sendInfo:該函數(shù)實現(xiàn)給某個特定用戶發(fā)送一條信息的功能,函數(shù)原型如下:</p><p> publ
36、ic static void sendInfo(Socket client,String info) throws IOException</p><p> ?、芎瘮?shù)getIP:該函數(shù)實現(xiàn)從socket中得到用戶的ip地址的功能,函數(shù)原型如下:</p><p> public static String getIP(Socket socket) </p><p>
37、 ⑤函數(shù)getIP:該函數(shù)實現(xiàn)從一個hashtable中根據(jù)value得到key的功能,函數(shù)原型如下:</p><p> public static String getIP(Hashtable ip2nickname,String nickname)</p><p> ?、藓瘮?shù)getNickname:該函數(shù)實現(xiàn)從socket和IP地址——昵稱對照hashtable中得到用戶的昵稱的功
38、能,函數(shù)原型如下:</p><p> public static String getNickname(Socket socket,Hashtable ip2nickname)</p><p> ?、吆瘮?shù)updateOnLineUsersList:該函數(shù)實現(xiàn)將在線用戶列表的顯示清空,并用最新的用戶列表更新客戶端的用戶列表,只顯示昵稱,函數(shù)原型如下:</p><p>
39、; public static void updateOnLineUsersList(List onLineUsersList,String allNickname)</p><p> ?、嗪瘮?shù)updateOnLineUsersList:該函數(shù)實現(xiàn)將在線用戶列表的顯示清空,并用最新的用戶列表更新服務器端的用戶列表:顯示的是ip:昵稱,函數(shù)原型如下:</p><p> public st
40、atic void updateOnLineUsersList(List onLineUsersList,Hashtable ip2nickname)</p><p> ?、岷瘮?shù)getSocketByIP:該函數(shù)實現(xiàn)根據(jù)用戶ip地址得到該用戶所在的socket功能,函數(shù)原型如下:</p><p> public static Socket getSocketByIP(ArrayList
41、onLineUsers,String ip)</p><p> ?、夂瘮?shù)getServiceByIP,該函數(shù)實現(xiàn)根據(jù)用戶ip地址得到該用戶所在的service功能,函數(shù)原型如下:</p><p> public static Service getServiceByIP(ArrayList allService,String ip)</p><p> 4.2客戶
42、端設計與編碼</p><p> 由于服務器端需要一次處理多個客戶端的請求,所以客戶端的設計均使用了Java的多線程處理機制實現(xiàn)。</p><p> 4.2.1客戶端程序</p><p> 該段功能由Client.java文件中的Client類實現(xiàn)(程序代碼請見附錄),具體實現(xiàn)過程如下:</p><p> ?、傩陆蛻舳耍撼跏蓟摽蛻舳说?/p>
43、監(jiān)聽器、套接字、在線用戶列表以及發(fā)送消息的String流,并且將客戶端連接狀態(tài)設置為真。初始化一個客戶端時,需要用到該客戶端的IP地址、端口號、在線用戶列表以及聊天內容列表等信息。</p><p> ?、诮⒈O(jiān)聽:創(chuàng)建一個BufferedReader以及一個PrintStream之后,再通過多線程機制建立對服務器發(fā)來消息進行監(jiān)聽的監(jiān)聽器Listener。</p><p> ③發(fā)送消息:客
44、戶端循環(huán)發(fā)送消息給服務器,直到發(fā)送的String流遇到結尾字符。</p><p><b> 4.2.2文件發(fā)送</b></p><p> 該段功能主要實現(xiàn)文件發(fā)送,默認端口為9900,由FileSender.java文件中的FileSender類實現(xiàn)(程序代碼請見附錄),具體實現(xiàn)過程如下:</p><p> ?、俪跏蓟菏褂媒邮斩擞脩舻年?/p>
45、稱、需要被傳輸?shù)奈募约傲奶煊涗浟斜沓跏蓟疐ileSender相應的屬性。</p><p> ②用需要被傳輸?shù)奈募陆ㄒ粋€文件輸入流,通過該文件輸入流新建一個緩沖輸入流,用于緩沖文件輸入數(shù)據(jù);同時使用接收端用戶的IP地址以及端口號新建一個套接字,并通過該套接字建立一個緩沖輸出流,用于文件輸出數(shù)據(jù)的緩沖及刷新,然后使用一個字節(jié)數(shù)組用于讀取文件數(shù)據(jù)。</p><p> 初始化進度條:
46、設置其最小值為零,最大值為文件長度除以字節(jié)數(shù)組長度。</p><p> ?、馨l(fā)送文件數(shù)據(jù):循環(huán)從字節(jié)數(shù)組中讀取數(shù)據(jù),若沒有到String流的結尾,則更新count值為原值與此時字節(jié)數(shù)組的長度之和,根據(jù)此時的count值修改進度條的值,再將字節(jié)數(shù)組中的數(shù)據(jù)寫入到用于輸出的套接字中,并刷新輸出流。</p><p> ?、蓐P閉輸入輸出流以及建立的套接字,系統(tǒng)使用對話框提示用戶文件發(fā)送成功,再
47、次將進度條設置為不可見,文件長度設置為零,以便下一次文件傳輸使用。 }</p><p><b> 4.2.3文件接收</b></p><p> 該段功能主要實現(xiàn)文件接收,默認端口為9900,由FileReceiver.java文件中的FileReceiver類實現(xiàn)(程序代碼請見附錄),具體實現(xiàn)過程如下:</p><p>
48、; ?、俪跏蓟菏褂眯枰粋鬏?shù)奈募约傲奶煊涗浟斜沓跏蓟疐ileReciever相應的屬性。</p><p> ②用需要被傳輸?shù)奈募陆ㄒ粋€文件輸出流,通過該文件輸入流新建一個緩沖輸出流,用于緩沖文件輸出數(shù)據(jù)及刷新;同時使用發(fā)送端用戶的端口號新建一個服務器套接字,并通過該套接字的accept()方法建立一個緩沖輸入流,用于文件輸入數(shù)據(jù)的緩沖,然后使用一個字節(jié)數(shù)組用于讀取文件數(shù)據(jù)。</p>
49、<p> ?、劢邮瘴募?shù)據(jù):循環(huán)從字節(jié)數(shù)組中讀取數(shù)據(jù),若沒有到String流的結尾,則更新count值為原值與此時字節(jié)數(shù)組的長度之和,根據(jù)此時的count值修改進度條的值,再將字節(jié)數(shù)組中的數(shù)據(jù)寫入到用于輸出的文件中,并刷新輸出流。</p><p> ?、荜P閉輸入輸出流以及建立的套接字,系統(tǒng)使用對話框提示用戶接收文件成功,再次將進度條設置為不可見,文件長度設置為零,以便下一次文件傳輸使用。 <
50、;/p><p><b> 4.2.4消息監(jiān)聽</b></p><p> 該類主要實現(xiàn)對服務器發(fā)送的消息進行監(jiān)聽的功能,由Listener.java文件中的Listener類實現(xiàn)(程序代碼請見附錄),具體實現(xiàn)過程如下:</p><p> ?、偈褂镁彌_輸入流、在線用戶列表以及聊天記錄列表初始化Listener對象的相關屬性,并啟動多線程。<
51、/p><p> ②循環(huán)接收從服務器發(fā)送來的信息,直到輸入流讀到了String流的末尾,接著開始判斷消息的類型。</p><p> ③若控制字以“NICKNAME”開始,則證明需要更新用戶列表,此時客戶端進行相關操作。</p><p> ④如控制字以“FILEECFO”開始,則客戶端需要通過控制字以后的字符獲得目的端的IP地址。</p><
52、p> ?、萑艨刂谱忠浴癋LENGHTH”開頭,則客戶端可以獲得需要傳輸?shù)奈募L度。</p><p> ?、奕艨刂谱侄疾粷M足②—⑤的條件,則將該信息作為是交談內容更新在聊天記錄列表中。</p><p><b> 4.3運行結果</b></p><p> 4.3.1服務器啟動服務</p><p> 4.3.2
53、客戶端登陸</p><p> 4.3.3服務器實現(xiàn)其管理功能</p><p> ?、傧蛩锌蛻舳税l(fā)送消息</p><p> 向某一個客戶端發(fā)送消息</p><p> 制修改某個客戶端的昵稱</p><p> 4.3.4客戶端向所有客戶端廣播</p><p> 4.3.5客戶端與客戶端間
54、實現(xiàn)“私聊”</p><p> 4.3.6客戶端與客戶端之間實現(xiàn)文件傳輸功能</p><p><b> ①文件發(fā)送</b></p><p><b> ?、谖募邮?lt;/b></p><p><b> 文件傳輸過程中</b></p><p><b
55、> 傳輸完成</b></p><p><b> 用戶離開</b></p><p><b> 服務器關閉</b></p><p><b> ?、踅Y論與總結</b></p><p><b> 5.1課程設計結論</b></p&g
56、t;<p> 通過4.3運行結果,可以看出,該課程設計利用Java應用程序Socket編程實現(xiàn)了以下功能:使用Java的多線程處理機制建立兩個套接字分別作為服務器端和客戶端。</p><p> 在服務器端實現(xiàn)了向各個客戶端發(fā)布系統(tǒng)消息,接受來自客戶端的各種信息并分別處理的功能,可以控制客戶端的連接以及對用戶的管理作用,并且能夠適時檢測已登錄用戶的連接狀態(tài)且刷新在線用戶列表,更能夠解析客戶端與服務
57、器端的消息交互并做出相應處理。</p><p> 在客戶端實現(xiàn)了向服務器端發(fā)布消息,并且對來自服務器的消息做出相應的響應,可以連接到特定的服務器,設置自己的昵稱,并且能夠監(jiān)聽服務器端發(fā)送過來的消息并做出相應的響應,更加能夠與其他用戶進行廣播或私聊,以及實現(xiàn)文件傳輸?shù)裙δ堋?lt;/p><p> 由此,可見,本次課程設計完成了最初的設計要求,即實現(xiàn)了類似P2P的QQ聊天系統(tǒng),有相應的客戶端和
58、服務器端;服務器端可以記錄當前在線客戶列表,把客戶列表發(fā)送給每一個在線客戶,并實時刷新;任何一個用戶都可以和任意其它的用戶進行交互,即從在線客戶列表中選擇一個或一組其它用戶通過服務器的轉發(fā)彼此進行信息的交互以及文件的交互。</p><p> 5.2課程設計總結與體會</p><p> 在本次課程設計中,我們綜合應用所學過的知識,在使用Java應用程序的Socket編程機制的基礎上,根據(jù)
59、傳輸層的傳輸控制協(xié)議TCP協(xié)議的原理,設計點對點數(shù)據(jù)交換程序,并且實現(xiàn)服務器端和客戶端的主要功能。另外,根據(jù)自己編寫的程序,成功地實現(xiàn)了用戶之間的聊天及文件傳輸功能,這一次的課程設計,使我們掌握了網絡傳輸數(shù)據(jù)的概念、原理以及設計方法,也加深了對傳輸控制協(xié)議TCP的理解。通過本次課程設計,我們清楚地了解到TCP、UDP協(xié)議的原理及二者的區(qū)別,學會了網絡中數(shù)據(jù)傳輸?shù)幕靖拍?、基本原理和設計步驟、設計思路和調試步驟,體會到了程序設計結構在整個
60、設計中起到的重要作用,最終能夠清晰地解析計算機網絡中數(shù)據(jù)傳輸這一概念,為進一步的網絡知識學習奠定了基礎,并且完成對《計算機網絡》這門課程的綜合應用,真正體現(xiàn)了“學以致用”的機制。</p><p> 本次課程設計中,因為有老師的辛勤指導,我們設計小組對理論知識進行了充分研究,發(fā)揚了創(chuàng)新實踐精神,積極探索,努力勤勉,共同越過了設計路上的每一處障礙,攻克了一個又一個的難關。最終,友好的協(xié)作關系與團隊凝聚力促使我們順利
61、地完成了此次課程設計。</p><p> 本次課程設計,加深了我們對理論知識的理解,也鍛煉了我們的實踐能力,更多的是在實踐中收獲了太多的感觸和心得,.雖然計算機組成原理的課程設計已經結束,可我們明白“學無止境”的道理,我們會繼續(xù)刻苦鉆研,求實創(chuàng)新,不斷地用知識來充實自己,跟上科技時代前進的步伐。</p><p> 在此次的設計中,非常感謝老師對我們的幫助和指導。才疏學淺,過程難免還不夠
62、完善,望老師再次不吝賜教!</p><p> ?、?課程設計分工及參考文獻</p><p><b> 6.1課程設計分工</b></p><p> 劉龍:服務器端程序的設計以及實現(xiàn),包括服務器端的連接控制、管理作用、刷新列表以及消息處理等功能的實現(xiàn):服務器端界面的設計和窗口事件的處理,實現(xiàn)服務器端和客戶端的的登錄信息、聊天記錄功能的實現(xiàn)
63、.</p><p> 奉光陽:客戶端界面的設計和窗口事件的處理,以及實現(xiàn)客戶端的連接功能、登錄設計以及,提出消息處理的基本模式,以及客戶端消息處理功能的實現(xiàn),實現(xiàn)客戶端和服務器端的登錄信息、聊天記錄功能的實現(xiàn).</p><p><b> 。 </b></p><p> 韓超: 點對點信息交互的實現(xiàn),監(jiān)聽功能,文件傳輸進度條的開發(fā)與
64、實現(xiàn),搜集資料,文件傳輸機制的設計與實現(xiàn),同時對進度條和文件保存功能的實現(xiàn)。課程設計報告資料的搜集與整理,補充及修改課程設計報告</p><p> 體現(xiàn)了作為一個團隊應有的凝聚力,完成了本次課程設計。</p><p><b> 6.2參考文獻</b></p><p> [1]《計算機網絡》第4版 謝希仁 電子工業(yè)出版社 2003年6
65、月</p><p> [2]《用TCP/IP進行網絡互聯(lián)》(第一卷) D.E.Comer 電子工業(yè)出版社2004年11月第四版</p><p> [3]《TCP/IP網絡原理與技術》周明天、汪文勇清華大學出版社:1993</p><p> [4《Java程序設計之網絡編程》李芝興、楊瑞龍、朱慶生 清華大學出版社 2006年3月第一版 <
66、;/p><p><b> Ⅶ附錄 </b></p><p> 實現(xiàn)代碼(內容已被演說,僅附關鍵性代碼)</p><p> 7.1.1 服務器程序</p><p> //Server.java</p><p> 在服務器端維護一個hashtable,用來存放各客戶端的IP地址與用戶昵稱之間的對
67、照關系映射。</p><p> Hashtable ip2nickname=new Hashtable();</p><p> ArrayList allService=new ArrayList();</p><p> String clientIP=client.getInetAddress().getHostAddress();</p>&
68、lt;p> //判斷該客戶端已經連接的話,提示退出</p><p> if(ip2nickname.get(clientIP)!=null)</p><p><b> {</b></p><p> ChatTookit.sendInfo(client,"已經有客戶端從該ip地址連接服務器,本次連接將退出!");
69、</p><p><b> break;</b></p><p><b> }</b></p><p> //把新建連接的用戶加入當前用戶列表</p><p> onLineUsers.add(client);</p><p> //默認情況下,即在還沒有收到用戶自
70、定義昵稱的清空下,把用戶的IP地址做為其昵稱維護入ip2nickname</p><p> ip2nickname.put(clientIP,clientIP);</p><p> //在服務器端提示有新的客戶連接</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> //針對每個client連接啟動其特定服務線程</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、端連接時出現(xiàn)問題!", "提示",JOptionPane.INFORMATION_MESSAGE);</p><p><b> }</b></p><p><b> }</b></p><p><b> }</b></p><p> //強
75、制更改用戶的昵稱</p><p> public void changeNickname(String oldName,String newName)</p><p><b> {</b></p><p> //如果該昵稱已經被別人使用則不進行更改</p><p> if(ip2nickname.contains
76、(newName))</p><p><b> {</b></p><p> chatContent.add("該昵稱已經有人使用,所以不做任何更改");</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> //將負責該用戶的Service里的昵稱變量進行修改</p><p> Service service=ChatTookit.getServiceByIP(allService,ip);</p><p> service.c
79、hangeNickname(newName);</p><p> //刷新服務器端的顯示</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,"你已經被系統(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, "關閉客戶端"+ip+"時出錯!", "提示",JOptionPane.INFORMATION_MESSAGE);</p><p><b> }</b></p><p> //刷新服務器端的顯示<
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ā)送信息出錯!", "提示",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> //給某個特定用戶發(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> //客戶端的:第二個參數(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> //服務器端的:第二個參數(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ā)過來的信息顯示在服務器端面板上,并遍歷發(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> //如果用戶的昵稱已經被別的用戶使用,提示用戶重新起昵稱</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> //更新服務器端的顯示<
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> //是否是想對某個用戶發(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+" 給你,請點“保存”按鈕選擇要保存的位置,再點“開始”按鈕開始接收文件");</p><p> //將目標用戶的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)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 眾賞文庫僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
評論
0/150
提交評論