JAVA 的聊天室程式__JAVA

來源:互聯網
上載者:User
終於完成了這個實驗了,寫了報告以及 email 給老師了。
一直很懶,不過這個程式寫得還挺順利的,用 JAVA 進行網路編程和多線程編程很方便,只是介面編程比較麻煩點,不過為了省事我的介面做得挺簡潔的。
不過代碼寫得還是挺難看嘀,太緊湊了,個人還是比較喜歡自己編的 C++ 程式的代碼結構。
這個大概就是這個學期我唯一一件認真做的和課程相關密切的事情了。

工程檔案和程式已上傳,但是還在審閱中。。稍後可在http://download.csdn.net/user/Rappy/下載。

報告如下:
多線程多人聊天程式

實驗目的

編寫一個多人聊天的客戶/伺服器多線程聊天室程式。

理解TCP協議和多線程編程.。

瞭解聊天軟體的基本原理。

 

實驗內容

聊天室程式功能簡述:

聊天室程式分為伺服器端,和用戶端。

伺服器程式作為一個中轉站。所有用戶端都只與伺服器進行通訊。

用戶端程式以使用者名稱登入。

伺服器和用戶端都顯示線上的使用者列表。

使用者可以向所有使用者發表訊息。

 

實驗過程

(1)採用 Eclipse 作為開發工具,JAVA 為開發語言。

(2)使用 JAVA 的 Socket 和 ServerSocket 這兩個類可以在網路連接時不必關心底層操作,而使用DataInputStream 和 DataOutputStream 這兩個類可以像本地輸入輸出那麼方便。

擴充 JAVA 的 Tread 類,可以在進行多線程編程時不必關心阻塞等操作,只需要重載其運行方法 void run ();。

(3)訊息的格式是由格式首碼以及內容構成:

用戶端訊息:

”L user” 表示以 user 為使用者名稱來登入(log in)服務端;

“M XXX” 表示向服務端發送內容為 “XXX” 的聊天訊息;

“Q” 表示退出登入(quit)。

服務端訊息:

“A user1 user2 ”表示接受(accept)使用者的登入請求並向其發送線上使用者的名單;

“R” 表示拒絕(refuse)使用者的登入請求,假如使用者名稱已被佔用。

“M XXX” 表示服務端向線上使用者廣播內容為 “XXX” 的聊天訊息。

“L user” 表示名為 user 的使用者登入成功,向線上使用者發送該使用者登入的訊息。

“Q user” 表示名為 user 的使用者退出登入,向線上使用者發送其退出登入的訊息。

“Q” 表示接受使用者的退出登入請求。

(4)服務端

介面如下:

其中 Server IP 是原生 IP 位址,不可編輯,而 Server Port 是服務連接埠,點擊Start 按鈕即可以監聽該連接埠,而 Start 按鈕會變成 Stop 按鈕,再次點擊將會斷開所有使用者的串連,而重新變成 Start 按鈕。如下圖為服務狀態中:

 

(A)

服務端是由一個 Server 類構成,其定義為

public class Server extends Frame implements ActionListener{//…}

表示繼承了 JAVA 的架構類 Frame 並實現了 ActionLisstenner 的介面,即其是一個視窗,並可以監聽使用者的行為,如點擊按鈕。

主要變數有:

private boolean serving = false;

private ServerSocket server;

private Hashtable ht;          // 記錄 String userName -> DataOutPutStream out

private Hashtable ht_s;       // 記錄 String userName -> Socket connection

 

serving 是一個全域的布爾變數,表示是否在服務中。在點擊 start 按鈕後設為 true,點擊 stop 按鈕後設為 false。

server 是一個服務通訊端,用於監聽連接埠,接受使用者的串連請求。

ht 是記錄使用者名稱到串連該使用者的輸出資料流的雜湊表,用於向使用者廣播訊息。

ht_s 是記錄使用者名稱到串連該使用者的通訊端的雜湊表,用於停止服務時,斷開這些串連。

 

另外還包括了一些控制項,用於程式的介面中。

(B)

在 Server 類裡面有兩個嵌套類,都是擴充的線程類:

private class ServerThreadSingle extends Thread{//…}

private class ServerThread extends Thread{//…}

 

其中第二個是監聽使用者的登入請求的線程,主要代碼如下:

while(serving){

          Socket connection = server.accept();

          ServerThreadSingle handler = new ServerThreadSingle(connection);

}

即當服務的時候,接受使用者的串連請求,並開始一個單獨的服務線程(第一個線程類)和使用者進行通訊。

 

而第一個線程類的主要工作是

線上程類的建構函式中初始化一個布爾變數 login = false;

然後線上程類的 run() 方法中進行以下工作:

while (!login){

          // 讀取使用者發來的訊息。

          // 如果該訊息的格式首碼是 ‘L’ ,那麼判斷訊息是否包含使用者名稱

// 或者使用者名稱是否已存在於一個用於記錄使用者名稱的雜湊表 ht 中。

// 如果是,則回複訊息 “R”,表示拒絕。

// 如果否,則回複一條訊息 “A user1 user2 …”,表示接受。

// 其中user1, user2, …是當前所有線上使用者的名單,從雜湊表中讀取。

// 向這些線上使用者發送訊息 “L current_user” ,

// current_user 是當前登入的使用者所提供的使用者名稱。

// 向雜湊表中添加該使用者名稱。

// 在服務端的訊息輸出區中輸出使用者登入成功的訊息。

login = true;

}

while (login){

// 接收使用者的訊息

// 如果訊息的格式首碼是 ‘Q’,那麼回複訊息 “Q”,提示退出成功,

// 從雜湊表中刪除該使用者名稱,並廣播訊息 “Q current_user”。

// 否則將訊息加上目前使用者名並廣播給所有使用者(包括目前使用者)。

// 在服務端的訊息輸出區中輸出訊息。

}

// 關閉串連

(C)

     事件處理方法,用於程式介面響應按鈕點擊的事件。

public void actionPerformed(ActionEvent event){//…}

在點擊 start 按鈕後,將 serving 設為true,並建立一個服務通訊端和啟動服務線程,其中需要從介面中讀進服務連接埠的設定值。然後 start 按鈕變為 stop 按鈕。

點擊 stop 按鈕後,將 serving 設為 false,並斷開所有串連,然後 stop 按鈕變為 start 按鈕。

(5)用戶端

     介面如下:

   

     其中的 User Name 需要填入自己的使用者名稱(初始化為 User),Server IP 需要填入

伺服器的 IP 位址(初始化為本機 IP),Server Port 需要填入伺服器的監聽連接埠

(預設是 8888,無需更改)。然後點擊 Login 按鈕即可向伺服器發送登入請求。

登入後,在訊息文本輸入區中輸入聊天訊息後,點擊 Send 按鈕即可發送訊息。

點擊 Logout 按鈕可以退出登入。如下圖,為聊天狀態(在另外一台機器上運行):

(A)

用戶端是由一個 Client 類構成,其定義為:

public class Client extends Frame implements ActionListener{//…}

表示繼承了 JAVA 的架構類 Frame 並實現了 ActionLisstenner 的介面,即其是一個視窗,並可以監聽使用者的行為,如點擊按鈕。

主要變數有:

private boolean login = false;         // 記錄是否登入的布爾變數

private Socket connection;           // 用於和服務端串連的通訊端

private recThread receiver;           // 用於啟動接收服務端訊息的線程

 

另外還包括了一些控制項,用於程式的介面中。

(B)

在 Client 類的時間處理方法中分別處理來自按鈕 Login,Send,Logout的時間,其中主要是分別調用 logIn (),sendMsg (),quit () 這三個方法。

logIn () 方法主要是從介面中擷取登入資訊,向服務端發送登入訊息

“L userName”。如果服務端返回的訊息是 “R” 則提示使用者 “User name error”,如果是”A user1 user2…” 則將 ’A’ 後面的使用者名稱添加到介面控制項的 list 中,然後啟動一個接收服務端訊息的線程receiver,稍後解釋這個線程。

 

sendMsg () 方法主要是從介面的訊息文本輸入區擷取訊息,加上 ”M “ 首碼然後向服務端發送訊息。

 

quit () 方法主要是向服務端發送訊息 ”Q”。

(C)

用於接收服務端訊息的線程receiver 是一個嵌套類,擴充了線程類 Thread,其定義如下:

private class recThread extends Thread{//…}

在其 run () 方法裡面主要工作是:

讀取服務端的訊息。

如果首碼是 ‘L’,那麼將 ‘L’ 後面的 userName 加入介面控制項 list 中。並在訊息文本輸出區提示該使用者已登入。

如果首碼是 ‘Q’,那麼判斷 ‘Q’ 後面是否跟著 userName,如果是則將 userName 從介面控制項 list 中刪除,否則即為本用戶端退出成功,清除 list 裡面的所有使用者名稱。並在訊息文本輸出區提示該使用者已退出。

如果首碼是 ’M’,那麼將訊息輸出到訊息文本輸出區中。

 

(6)其他

在Server 類和 Client 類的建構函式裡面的主要工作是添加按鈕的事件監聽器,以及調用 setup () 方法,使用布局管理器將控制項按照一定的布局添加到介面中。

介面包含了一個 List 類的控制項 list,用於顯示線上使用者名稱單。

 

實驗總結

主要參考了《JAVA 語言程式設計》(清華出版社,朱福喜編著),瞭解到介面編程,多線程編程和網路編程的基本要點。

參考線上文檔,瞭解到 Hashtable, List 類的使用方法。

從本次

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.