UDP协议的Socket通信简介
UDP(User Datagram Protocol),用户数据报协议,不是一个基于稳定连接的协议,使用UDP协议通信不需要通信的两个端点间建立连接,通信的端点既可以作为发送端也可以作为接收端;与TCP 协议之间的不同在于, UDP 不是一种基于稳定连接的通讯协议。UDP 协议将独立的数据包从一台计算机传 输到另外一台计算机,但是并不保证接受方能够接收到该数据包,也不保证接收方 所接收到的数据和发送方所发送的数据在内容和顺序上是完全一致的。因此,UDP 协议更类似于快递的邮寄,快递的投递不能够保证能够被接收方及时收到,后发出的包裹也许会比先发出的包裹更早到达。
本项目用到了IO流和线程等java高级知识,基本原理是UDP实现,利用UDP协议的组播来实现发消息能离线发消息让接收方只要上线就能收到消息,利用线程收到组播发来的消息,UDP协议更适合TCP/IP协议开发这种聊天的程序。
1.TCP/IP协议: 需要有个服务端,还有客户端,必须客户端在线才能接受消息,现实中并不是这样,往往是离线的,所以这不适合本系统的开发,TCP/IP得到优点在于他可靠性和稳定性,
2.UDP协议: UDP 协议将独立的数据包从一台计算机传 输到另外一台计算机,但是并不保证接受方能够接收到该数据包,也不保证接收方 所接收到的数据和发送方所发送的数据在内容和顺序上是完全一致的。这一点就是这个群聊系统所需要的,所以选择了用UDP协议。
具体代码如下:
发送消息代码:
public class BroadcastSender {
/** 服务端口 */
public static final int PORT = 5678;
public static final String ADDRESS = "228.5.6.7";
public void startMulticast() throws IOException {
// 准备组播地址(D类IP地址)
InetAddress ip = InetAddress.getByName(ADDRESS);
// 创建组播Socket通道
MulticastSocket ms = new MulticastSocket();
//开启接受消息的线程
new BroadcastReceived(ADDRESS, PORT).start();
// 加入多播组
ms.joinGroup(ip);
//获取要发送消息
String msg = Units.sendMsg();
// 循环发消息
while (!Objects.equals(msg, "/bye")) {
String s = ip.getHostAddress() + ":" + msg;
// 将数据打包为数据报包
DatagramPacket dp = new DatagramPacket(s.getBytes(), 0, s.getBytes().length, ip, PORT);
//将消息发送给这个组播中的 所有人
ms.send(dp);
//循环接受要发送消息的内容
msg = Units.sendMsg();
}
//关闭通道
ms.close();
}
public static void main(String[] args) throws IOException {
new BroadcastSender().startMulticast();
}
接受消息代码:
public class BroadcastReceived extends Thread {
private String ip1;
private int prot;
public BroadcastReceived(String ip1, int prot) {
super();
this.ip1 = ip1;
this.prot = prot;
}
@Override
public void run() {
try {
// 准备组播地址(D类IP地址)
InetAddress ip = InetAddress.getByName(ip1);
// 连接组播Socket通道
MulticastSocket ms = new MulticastSocket(prot);
//加入组播
ms.joinGroup(ip);
// 接受组播的消息
while (true) {
//获取组播通道发过来的消息
String msg = Units.receive(ms);
//输出消息
System.out.println(msg);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
工具类代码:
public class Units {
/**接受组播发过来的消息*/
public static String receive(MulticastSocket ms) throws IOException {
// 声明一个字节缓冲区,用于从通道中获取的字节数据
byte[] b = new byte[1024];
// 声明一个数据报(空)接受通道中传输过来的数据
DatagramPacket dp = new DatagramPacket(b, b.length);
// 从通道中获取消息
ms.receive(dp);
// 将字节数组中的有效数据解析为字符串
String s = new String(b, 0, dp.getLength());
// 返回接受的的消息
return s;
}
// 发送消息
public static String sendMsg() {
Scanner sc = new Scanner(System.in);
String msg = sc.nextLine();
return msg;
}
}