即时通讯,即发送了消息后对方马上收到,一般用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配置文件下
的xxx改为你的数据库密码
请把客户端的TCPConnection类的
private TCPConnection() {
try {
client = new Socket("192.168.1.106", 8888);
.....
"192.168.1.106"改为你服务器的ip地址,才能正常运行。
一个路由器就是一个局域网,已经能正常运行。qq.sql脚本里创建6个默认用户。目前实现的功能:聊天、聊天记录保存(在record目录下保存)、上线未读消息提醒。请期待后续更新。
下面是截图,一张是运行截图,一张是聊天记录文件的截图,你可能需要两台电脑登录两个账号才能开聊。(一台开启服务器和一个客户端,另一台开另一个客户端)