基于UDP协议实现的Java聊天室

转载请注明出处,谢谢!(原文链接:https://chensian.github.io/2016/05/24/chat-udp/

Github :https://github.com/chensian/Chat-UDP

项目环境

eclipse EE

JDK1.8 + Mysql

摘要

本聊天室系统是采用C/S架构设计的JAVA语言编写的聊天系统。该聊天系统具有完整的会话功能,服务器具有侦听服务,转发聊天信息,响应用户下线,发送系统消息的功能。客户端具有登陆,断开连接,发送聊天信息,接收聊天信息的功能。该聊天室由服务端和客户端组成,主要用到Socket通信的网络应用。

模块分解

功能需求分析

聊天室客户端需求分析

(1)基本功能即可以即时通讯

(2)可以查询在线用户基本信息

(3)可以进行群聊

(4)可以进行私聊

(5)可以显示在线用户列表

(6)可以离线接收信息

聊天室服务器端需求分析

(1)可以显示在线用户基本信

(2)可以显示用户发送的聊天信息的基本情况(信息内容)

UDP协议

UDP协议的几个特性

(1)UDP是一个无连接协议,传输数据之前源端和终端不建立连接,当UDP它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。

(2) 由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。

(3) UDP信息包的标题很短,只有8个字节,相对于TCP的20个字节信息包的额外开销很小。

(4) 吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、源端和终端主机性能的限制。

(5)UDP使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的链接状态表(这里面有许多参数)。

(6)UDP是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付给IP层。既不拆分,也不合并,而是保留这些报文的边界,因此,应用程序需要选择合适的报文大小。

TCP与UDP比较

(1)UDP是无状态的,该协议使得数据传输的速度得到大幅度的提高。视频聊天语音聊天基本都是用UPD协议。 TCP接到客户端请求后马上做一个线程,将连接对象传递进去进行处理!但是UDP的话是没有连接对象的,只要消息包的概念!
(2)TCP是面向连接的,有比较高的可靠性,一些要求比较高的服务一般使用这个协议,如FTP、Telnet、SMTP、HTTP、POP3等,而UDP是面向无连接的,使用这个协议的常见服务有DNS、SNMP、QQ等。

Java UDP 技术

DatagramPacket类说明

该类表示一个数据报包。该数据报包用来实现一个无连接包的传送服务。它是进行数据报通信的基本单位。包含了IP地址、端口号和需要传输的数据等。在发送和接收数据报时,要创建DatagramPakcet类对象作为数据的载体。

构造函数

(1)public DatagramPacket(byte ibuf[],int ilength)

功能:创建一个用于接收数据报的DatagramPacket类对象。

参数:

buf:存储数据报的缓冲区。在数据报通信中,发送和接收一个数据报,都需提供一个缓冲区,用来安置发送和接收到的数据报。

length:接收数据报的长度,必须小于等于ibuf.length。

(2)public DatagramPacket(byte ibuf[],int ilength,InetAddress iaddr,int iport)

功能:创建一个用于发送数据报的DatagramPacket类对象。

参数:

buf:存储数据报的缓冲区。

length:发送数据报的长度,必须小于等于ibuf.length。

addr:数据报要发送到的目的IP地址。

port:数据报要发送到的目的地址的端口号。

常用方法

(1)public synchronized InetAddress getAddress()

功能:返回存放在接收或发送的数据报中的IP址。

(2)public synchronized int getPort()

功能:返回存放在接收或发送的数据报中的端口号。

(3)public synchronized byte[] getData()

功能:返回存放在数据报中的数据。

(4)public synchronized int getLength()

功能:返回数据报中数据的长度。

(5)public synchronized void setAddress(InetAddress addr)

功能:设置发送数据报的目的地址为iaddr。

(6)public synchronized void setPort(int port)

功能:设置发送数据报的目的地址的端口号为port。

(7)public synchronized void setData(byte ibuf[])

功能:设置数据报中的数据内容为字节数组ibuf的数据。

(8)public synchronized void setLength(int ilength)

功能:设置数据报中的数据的长度为ilength。

DatagramSocket类说明

该类表示用来发送和接收数据报包的套接字(Socket)。要收发DatagramPacket,必须打开一个数据报套接字(Datagram Socket)。

在Java中,数据报套接字通过DatagramSocket类来创建和访问。

构造函数

(1)public DatagramSocket() throws SocketException

功能:创建用于数据报通信的socket对象,由本地主机自动指定的一个可用的端口号。

(2)public DatagramSocket(int port) throws SocketException

功能:创建用于数据报通信的socket对象,并且把它绑定到本地主机指定的端口port。

(3)public DatagramSocket(int port,InetAddress addr) throws SocketException

功能:创建用于数据报通信的socket对象,并绑定到指定的本地地址addr的指定端口port。端口号port必须为0和65535之间的一个。

常用方法

(1)public void send(DatagramPacket p) throws IOException

功能:从此socket发送数据报包。

(2)public synchronized void receive(DatagramPacket p) throws IOException

功能:从网络接收一个UDP数据报包。存储在DatagramPacket类对象p中。该数据报包还包含发送方的IP 地址和发送方主机的端口号。

(3)public InetAddress getLocalAddress()

功能:获取该socket绑定的本地地址。

(4)public int getLocalPort()

功能:获取该socket绑定的本地主机的端口号。

(5)public void close()

功能:释放该数据报socket所占用的端口。

详细设计

服务器端介绍

1)newsPush(String, DatagramPacket)

说明:登录时,离线消息推送。

2)sendAll(Message, DatagramPacket)

说明:群发消息

3)sendONE(Message, DatagramPacket)

说明:私聊私发消息

4)register(User, DatagramPacket)

说明:注册事务处理

5)login(User, DatagramPacket)

说明:登录事务处理

客户端介绍

1)登录失败:用户名或者密码错误,返回200

2)登录成功:服务器返回211

3)重复登录,服务器对此ID的原登录客户端返回201

4)登录时,对密码传送进行加密(采用md5计算摘要法),发送换算好后的password传输至服务器。

5)类型与长度:

用户名:固定10位的数字(注册人的学号)组成。

密码:6~8位,仅接受由数字或字母组成的密码。

1
2
3
(用户名和密码格式设置错误了,服务器将会返回100)
(用户名重复,服务器将会返回101)
(注册成功,服务器返回111)
聊天室

1)clearMessage()

说明:清空聊天窗口记录

2)exit()

说明:退出聊天室

3)sendMessage()

说明:发送消息,可以选择群聊或私聊

4)changeUser()

说明:切换聊天好友。

工具类
java对象与字节数组相互转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public static byte[] ObjectToByte(java.lang.Object obj) {
byte[] bytes = null;
try {
// object to bytearray
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(obj);
bytes = bo.toByteArray();
bo.close();
oo.close();
} catch (Exception e) {
System.out.println("translation" + e.getMessage());
e.printStackTrace();
}
return bytes;
}
public static Object ByteToObject(DatagramPacket inPacket) {
byte[] bytes = inPacket.getData();
Object obj = null;
try {
// bytearray to object
ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
ObjectInputStream oi = new ObjectInputStream(bi);
obj = oi.readObject();
bi.close();
oi.close();
} catch (Exception e) {
System.out.println("translation" + e.getMessage());
e.printStackTrace();
}
return obj;
}
结果状态码

运行界面
注册界面

注册失败

聊天室界面

群发消息

私聊功能

离线接受功能

陈世强 wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
坚持原创技术分享,您的支持将鼓励我继续创作!