【Java學習】聊天室專案(32)

噹噹和嘟嘟發表於2019-02-19

聊天室專案需求:
1、使用者名稱登入註冊(判斷有沒有重複使用者名稱,可設定ip和埠)
2、上下線提醒
3、線上列表
4、私聊
5、公聊
6、傳送文字,檔案。
7、聊天記錄 儲存 查詢 刪除。
8、下線

選做功能
1、切換狀態(線上,隱身,忙碌)
2、建群
3、大檔案傳輸。(新建流傳輸)*
4、離線訊息*
5、個人資訊設定
6、語音聊天*
7、朋友圈
8、文字表情
9、增刪好友,修改好友備註名。

1.首先你得寫一個客戶端,一個伺服器端,利用TCP協議連線,先實現客戶與伺服器端聊天,我們開啟子執行緒專門負責接收訊息,主執行緒負責發訊息.如果你還不會 點選這裡

2.然後這只是初期,我們一步一步來,我們是不會和服務區聊天的,伺服器只是用來轉發訊息的,我們多個使用者連線到伺服器上,所有訊息通過伺服器轉發給接收者,所以我們得在伺服器端設定一個迴圈監聽,若有客戶端連線,則就為他開啟一個子執行緒,將他的名稱和他所對應的管道(socket)存到集合(可用hashMap雙列集合)中去,這樣的話,每一個客戶端自己都有一個主執行緒負責傳送訊息,都有一個子執行緒負責接收訊息,客戶端連線上伺服器後,伺服器為每個執行緒開啟一個子執行緒,給客戶端提供服務.

3.若李四和王五都已經連線了伺服器,當李四要給王五發訊息時候,先將訊息發給伺服器,經由伺服器轉發給王五,所以此時要規定訊息格式,要讓伺服器知道這個訊息是給王五的,不是轉發給趙六的,例如規定格式為 接收者#訊息內容#訊息標誌位#傳送者,類似的格式,這樣伺服器端根據已經定好的格式,對收到的字串進行按#擷取,就可以拿到接收者是誰,訊息是什麼,等資訊.

4.在改進一下,再伺服器端再寫一個註冊執行緒,再寫一個登陸執行緒,客戶端連線上伺服器的時候,讓他選擇是登陸還是註冊,進入不同的子執行緒,當登陸或註冊成功後,自動開啟伺服器端子執行緒,為客戶端提供服務,在客戶端連線的時候,先進行註冊,讓使用者端輸入使用者名稱,輸入密碼,(為後面寫登陸做準備)伺服器端就接受到後,(用Properties屬性集合)對這種使用者名稱密碼的鍵值對資料用檔案(以後可用資料庫)儲存起來,當註冊成功後,再開啟服務端子執行緒,為客戶端提供服務.

5.當使用者上線之後,應該對所用的現在使用者傳送上線提醒,某某某上線了.所以剛才當客戶端登陸的時候,將他們們的資訊儲存再集合裡面就用到了,就可以遍歷集合,給別的人,傳送上線提醒.

6.在客戶端註冊程式碼之後(此時已經連線上客戶端了,客戶端子執行緒也開啟了,為你提供服務了),客戶端主執行緒再寫一個switch-case可以用於功能的選擇,比如你要私聊,還是公聊,要發檔案,切換狀態,檢視聊天記錄,退出等功能.

下面我說一下寫這些功能我的想法,每個人的想法不一樣,求同存異啊.
首先需要定義一些常量,用於判斷該開啟那個功能,在客戶端請求伺服器的資料中加上這個常量,伺服器端收到資料後,對資料進行以之前規定好的#號拆分,根據拆分得到的常量(單獨寫一個類,對每一個功能都定義一些靜態常量,利用這些常量,來區別功能,讓伺服器知道,你發來的請求是幹什麼用的,或者使用列舉也可以)就可以判斷該是私聊,還是公聊,這種的功能選擇.

伺服器端的集合中存有每個線上的人的管道(socket),私聊就是,將訊息通過管道獲取流(getOutputStream)轉發給收信者,公聊是遍歷集合,轉發給所有線上的人.獲取線上列表就是將集合中的使用者名稱,拼接成一個字串當作伺服器的訊息,轉發回來.
要做隱身功能的話,可以在new一個單列集合arrayList或者hashSet,在使用者登陸成功或註冊成功時候,不僅將使用者名稱和對應的管道存到雙列集合中,而且再將使用者名稱存進單列集合中,在切換狀態的時候,只需要將單列集合中的使用者名稱刪除,在獲取線上列表的時候,將原來遍歷雙列集合變為現在遍歷單列集合,雙列集合不動,只用作公聊的時候用,隱身也是可以收發訊息的,只是別人獲取線上列表的時候獲取不到.

在收發檔案時候,利用一個小技巧,將前10kb用作每次傳送的指令訊息(接收者#訊息#訊息標誌位#傳送者)的位元組數,在將檔案的位元組數加到這10kb後面,當伺服器收到的時候,將緩衝區設定為10kb,都是先一次性讀取10kb訊息指令,當讀到的訊息之類中的訊息標誌位位發檔案的時候,就跳到收檔案的功能上,在這個方法中再次讀取檔案部分,這種方法可以滿足,傳送較小的檔案mb級別的.這其中用到了記憶體操作流(ByteArrayOutputStream())可以用來拼接位元組.如果傳送的檔案比較大,可以考慮先上傳到伺服器端儲存,再由接收者從伺服器端下載.
收發檔案會有一個問題,就是,你的客戶端子執行緒是收資訊的,當客戶端反饋回訊息,有人給你發來了一個檔案,此時你是沒法輸入資訊的,因為你的主執行緒現在停留再錄入訊息的狀態上,所以子執行緒沒法輸入訊息,此時可以寫一個共享變數,利用主執行緒的輸入,改變共享變數的值,子執行緒迴圈讀取共享變數,若共享變數變了,則讀取break,這樣以達到子執行緒獲取輸入的資料的方法,點選詳見

程式碼執行圖示:
在這裡插入圖片描述
在這裡插入圖片描述

程式碼太多,我打包在github中了


謝謝

相關文章