我是一個新手,學習了Socket通信后,寒假花了20天寫了這個小項目,只有一個客戶端,而且也是一個尚未完工的客戶端,服務器端只用來接收,轉發或保存消息。本不準備發出來的,因為項目還在編寫當中,實現的功能不多,且一些細節還沒有處理好,以后還會再寫一個比較細致的版本,不過老師要求了,就動手寫了這篇總結。
?
項目名稱: 大山QQ , 用以紀念我的大三 。
?
項目意義 :對相關知識點的一個綜合練習,熟悉Java通信方面的類的用法及組件的應用,記錄我大三的學習痕跡。
?
通信協議 :字節流協議
?????????????
功能 :
1.注冊
2.查找
3.添加/刪除好友
4.添加/刪除分組
5.好友上下線提醒
6.發送在線離線消息
7.發送在線離線文件
?
界面 :全部采用空布局,所有組件都是通過setBounds(....)方法添加的
?
具體流程 :
?
服務器端
:
?????????? 服務器端還沒有怎么寫,只實現了基本的消息傳送功能。
??????????? 開啟服務器以后,首先讀取所有的用戶信息,等待客戶端的鏈接。由于尚未學習數據庫,所有的用戶信息都是
以文件形式保存的。當開啟服務器后,讀取的所有用戶信息都保存在輔助靜態類ChatTool的一個用戶Map<User_ID,User>中,當客戶端連接上后,若為登錄消息且ID和password都正確,則將Client_Thread(服務器端的用戶通信線程類)添加至ChatTool類的線程Map<User_ID,Client_Thread>中,當客戶端向流中寫入消息后,對應服務器通信線程讀取該消息,并作出對應操作。
?
客戶端
:
?
1.登錄
?賬號密碼框只能輸入10位以內的數字0到9,實現方法有兩種 1.添加DocumentListener 2.添加keyListener
??????????????????????????????????? 具體見包MyComponent下的MyJTextField類
界面中的找回密碼,設置只是按鈕,還未添加功能。
?
若是賬號密碼均正確,服務器回發個人信息,包括賬號,簽名,頭像,以及好友信息,未讀消息等,建立緩存,存儲好友的頭像,然后轉入好友列表界面。??
?
這一步有待改進,頭像的字節長度遠遠大于其他信息的字節長度,在本機建立好友頭像緩存,可以減少信息的傳輸,提高通信速度。?
?
?改進方法:登錄前檢測本機好友頭像的個數,傳送登錄信息時加上本機好友頭像的好友ID,服務器只回發其他好友的頭像以及更改了頭像的好友頭像即可。這一步更麻煩了,不過通信效率的提升很可觀。
?
?
2.注冊
?
做注冊界面時,重要的就是在發送注冊消息前先檢測輸入的數據是否合法,并予以提示
?
?
當所有的信息都無誤了,再向服務器發送消息。若注冊成功,服務器端保存用戶信息,我最開始是用一個文件保存的,
后來做其他功能時發現要修改用戶信息時會很麻煩,后改為每一項信息保存為一個文件。
注冊成功,回發消息,提示,返回登錄界面。
?
做注冊功能的時候,我意識到應該要有容錯處理,一切數據都合法的情況下再提交至服務器。
?
3.好友界面
界面上的所有圖標都是JButton,setIcon(icon),沒有什么用處,主要是仿QQ,以后添加功能方便些
JTree顯示好友,頭像,賬號,昵稱,是否在線,簽名
具體功能有5個
????? 1.添加/刪除分組?? 2.刪除好友?? 3.搜索用戶(search)? 4.雙擊好友頭像,彈出聊天界面
?
4.用戶查找界面
?
ID查找和昵稱查找等的實現方法是相同的,所以就只做了一個ID查找
服務器讀取要查找的用戶ID,若存在就回發該用戶ID,昵稱等模糊查詢回發的就是所有滿足搜索條件的用戶信息
?
當點擊添加好友時,服務器接收到消息后首先檢查被添加用戶是否在線,在線發送消息,不在線就在被請求用戶未讀消息目錄下的聊天消息下生成一個文件,寫入消息。當被請求者用戶上線時,服務器發送其信息時包含這些未讀消息,同時刪除未讀消息文件。
?
這是另一個我覺得很重要的地方----要保證信息的不丟失
?
比如A請求添加B為好友,首先A向服務器發送請求消息,為保證B收到請求,?若B不在線,則將請求保存到B的未讀文件中,在其上線時讀取自身信息時(服務器在發送完溫度消息后刪除該消息),在通知B,若B在線則直接向其發送消息。B接收請求,選擇分組,刷新界面,同時向服務器發送消息,服務器在保存信息,同時通知A結果,A在選擇分組,刷新界面,再將結果發到服務器保存。
?
就是將客戶端的一切改動都發到服務器保存下來。做修改個人信息的功能的時候,比如修改昵稱,簽名,密碼等也是一樣的
過程。
5.好友上下線提醒
?
我覺得這個功能的實現是這個項目最有價值的地方。采用了觀察者模式。
?? 具體做法如下:
?? 自定義一個接口MsgListener,含有方法ReceiveMsgAction(Msg msg);
自定義一個接口subject,含有方法addMsgListener(MsgListener l),removeMsgListener(MsgListener l),
??? fireMsgListener(Msg msg);
??? 客戶端的通信線程類ClientThread繼承Subject
????定義類MyJTree_AsListeber extends JTree implements MsgListener ,重載ReceiveMsgAction(Msg msg),創建對象時,將之注冊到對應的通信線程上。當對應通信線程類對象調用fireMsgListener(Msg msg)時,通知JTree對象作出相應顯示刷新。
?
??? 之前我一直都很追求外觀,可當老師第一次講到設計模式的時候,我才意識到純粹的最求外觀是沒什么意義的,最重要的還是程序的結構,一個好的軟件的設計應該是多種結構的綜合,結構的好壞決定了程序的拓展性和可維護性。至于技術點,最好是能讀懂源碼,理解原理,這需要經驗,現在的我還差得遠,對于技術只停留在用的階段,還未上升到理論。
?
?
6.聊天界面
?
?視頻語音截圖震動功能都沒實現
可以修改字體屬性,傳送消息,文件。未保存消息
?
?
?
?
震動的具體原理就是setLocation(x,y)方法的運用
截圖,遠程就是Robot類的應用
視頻功能需要JMF的相關知識,還沒有研究?
?
7.傳送文件
?
?流程如下:1.在線文件的傳送????? 先發送請求,對方同意后,開啟一個服務器(有堵塞,應該放在線程中),回發給發送者,然后發送者連上該服務器,開啟多個線程(我開啟的是2個線程),分段傳送文件,具體實現是RandomAccessFile類。
如DataImputStream類對象只能從文件的第一個字節開始讀,但RandomAccessFile類對象可以隨機讀取文件,調用seek(x),或者skipBytes(X)方法,改變指針位置,就可以實現隨機讀取某一位置的字節。迅雷下載就是這種原理。開始,不清楚seek(x),或者skipBytes(X)方法是如何改變文件指針的,是讀取X個字節再丟掉,還是直接改變指針在內存中的地址呢?經過測試,答案是后者。?? 2.離線文件的傳送???? 由于只有一個通信I/o,傳送文件應該另外創建Socket對象連上服務器,發送完文件后再關閉Socket。
?
?
?
?
?項目的不足 :
1.數據的存儲??? 文件存儲終究不如數據庫存儲,讀取速度慢,性能低。只適合小群體的聊天
2.結構???? 雖然嘗試使用了觀察者模式,但客戶端程序的耦合度還是比較高的,一個好的結構應該是多種設計模式的綜合
3.功能???? 功能比較少,而且有缺陷,比如還沒有加上遠程,視頻等功能,前幾天已經把遠程寫好了,不過對圖像的壓縮度
????????????? 感到不滿意,其他功能的細節也有待改進,比如在添加好友時,我沒有先判斷是否請求對象已是自身好友等,都
????????????? 是些細節的地方,還有修改個人信息的功能等等,這是都不難,但這些細節都決定著項目的友好性。很重要。
4.有一個問題沒有解決,好友查找界面,表格刷新時會包空指針的錯,沒找到具體原因。
5.代碼的結構不是很好,注解寫的少了
6.沒有創新?????? 純粹是技術的練習,嘗試使用了一個設計模式,沒有創新,沒什么價值
?
收獲 :
1.意識到結構和友好的重要性
2.在調試的過程中,第一次意識到Java程序對系統內存,CPU的占用問題,意識到了一些小問題,比如讀寫文件不關流的話,就不會釋放內存。
3.讓我的心情很平靜,不再浮躁
?
注:項目中的所有圖片都是截圖截下來的,在壓縮包的圖片文件夾中。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
