即時通訊,即發送了消息後對方馬上收到,一般用tcp或者udp協議來傳輸消息。我也是第一次深入學習tcp和udp的使用,編碼過程中遇到很多難題,自己辛辛苦苦百度,解決了一個又一個困難,但是個人的聽聞是有限的,希望能拋磚引玉,聽取到大家更好的解決辦法。
項目地址:http://download.csdn.net/detail/qq_27311165/9911099
首先,這個項目的服務器大部分bean用Spring來託管,Spring託管了項目的dao層和業務層(QQService)還有helper模塊(UDPHelper、TCPConnectionManager這兩個單例),而且都是單例。單例就可能牽扯到線程安全問題,dao都是單例,jdbc中,如果多個線程同時執行靜態方法DriverManager.getConnection()會拋出異常,所以將該靜態方法封裝到DBHelper的getConnection()方法中,加上synchronized使線程同步,因爲dao的方法除了dbHelper.getConnection();外其他都是訪問局部變量和參數,每個線程調用dao的方法時都有自己的局部變量和參數,所以dao現在是線程安全的。服務器其他部分經過我不停地取證,應該也是線程安全的。 客戶端,因爲我想急於驗證它和服務器的通訊,所以寫得非常簡便。客戶端讀者也可以用另外的語言編寫,只要發送的tcp和udp報文能被服務器解析(“報文規定.txt”已經在壓縮包中)。
數據庫只有3張表user、friend、unreadmsg。
CREATE TABLE user(
userid INT(8) PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(20) NOT NULL unique,
password VARCHAR(20) NOT NULL,
isonline boolean NOT NULL,
nickname VARCHAR(20) NOT NULL, #暱稱,網名
sex VARCHAR(4),
birthday DATE,
hometown VARCHAR(20),
livein VARCHAR(20),
motto VARCHAR(100) #座右銘,個性簽名
) ;
CREATE TABLE friend(
id INT(20) PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(20) NOT NULL,
friendname VARCHAR(20) NOT NULL,
friendnickname VARCHAR(20) NOT NULL,
fgroup VARCHAR(20) NOT NULL, #好友分組名,可以一個好友一個組
note VARCHAR(20) #好友備註
) ;
CREATE TABLE unreadmsg( #只有未讀消息纔有資格存進數據庫
id INT(20) PRIMARY KEY AUTO_INCREMENT,
sendername VARCHAR(20) NOT NULL,
receivername VARCHAR(20) NOT NULL,
msgtype int(4) NOT NULL,
sendtime VARCHAR(25) NOT NULL, #發送者發送到服務器時,服務器把當前時間賦給它
msg VARCHAR(200) NOT NULL
) ;
先來分析一下即時通訊軟件,什麼數據要被存到數據庫,用戶的信息肯定是要存到數據庫的,所以有了user表,用戶肯定要有自己的好友,friend表中username是自己的用戶名,後面4個字段分別表示好友用戶名、好友暱稱、好友所在分組名、備註名字。就這樣,我們就可以用一條記錄表示一個好友。最後是unreadmsg,未讀消息,如果好友不在線,就先把消息存到數據庫,等好友上線後,服務器從數據取出消息發給好友。
目前服務器和客戶端大部分是用tcp通信,只有發消息給好友時才用udp通信。爲了方便使用tcp,客戶端把Socket封裝到了TCPConnection這個單例類;爲了方便使用udp,客戶端把Socket封裝到了UDPHelper這個單例類。
客戶端可以在任何地方使用
TCPConnection.getInstance().sendAndWaitResponse(String msg); //只往服務器發消息,且等待迴應
和
TCPConnection.getInstance().justSend(String msg); //只往服務器發消息,不等待迴應
和
UDPHelper.getInstance().send(String content); //只往服務器發消息
發送消息給服務器。
我突然不想寫了,請自己參考其中的妙處。下載完壓縮包後
請把Spring配置文件下
<property name="dbpassword">
<value>xxx</value>
</property>
的xxx改爲你的數據庫密碼
請把客戶端的TCPConnection類的
private TCPConnection() {
try {
client = new Socket("192.168.1.106", 8888);
.....
"192.168.1.106"改爲你服務器的ip地址,才能正常運行。
一個路由器就是一個局域網,已經能正常運行。qq.sql腳本里創建6個默認用戶。目前實現的功能:聊天、聊天記錄保存(在record目錄下保存)、上線未讀消息提醒。請期待後續更新。
下面是截圖,一張是運行截圖,一張是聊天記錄文件的截圖,你可能需要兩臺電腦登錄兩個賬號才能開聊。(一臺開啓服務器和一個客戶端,另一臺開另一個客戶端)