文章目录
- 前言
- 一、UDP程序设计是什么?
- 二、使用步骤
- 1.数据包套接字与多播套接字
- 2.数据报包
- 3.实操展示
- 总结
前言
UDP协议程序相对于TCP协议,就是一个广播喇叭给全村人听和两个人说悄悄话的差别。因此UDP的数据传输效率比TCP高,可以同时分享给所有在场的人。缺点就是不能保证数据能完整地传送到接收方那里,这个就像喇叭一样了,谁知道对方听没听,UDP只管广播。UPD和TCP协议都可以看作数据通讯协议。
一、UDP程序设计是什么?
UDP程序设计是指使用用户数据报协议(UDP)进行网络通信的程序设计。
UDP 是一种无连接的协议,它提供了一种简单的、不可靠的数据传输服务。与传输控制协议(TCP)相比,UDP 不提供可靠的数据传输和流控制机制,但具有较低的延迟和较小的数据传输量。
UDP程序中,套接字负责接收或发送数据包,数据包负责保存数据内容,就像外卖小哥从一家店拿了外卖运送到各个门口一样,套接字是小哥,数据包是外卖。数据包套接字和多播套接字,两个套接字都是一回事,它们都是实现主机接收或发送数据包的类,只不过一个是父类一个是子类的关系。数
二、使用步骤
UDP协议的使用如下:
发送数据包
(1)使用MulticastSocket()创建数据包套接字对象(记得绑定接口)。
(2)将该数据包套接字使用joinGroup(InetAddress inet)方法加入指定的广播组地址(提前创建InetAddress对象,广播组地址范围:224.0.0.0~239.255.255.255)。
(3)使用DatagramPacket()的构造方法创建要发送的数据包对象。
(4)使用DatagramSocket()的send(DatagramPacket 数据包对象)方法发送数据包。
接收数据包
(1)使用MulticastSocket(int port)创建数据包套接字,绑定到指定端口。
(2)将该数据包套接字使用joinGroup(InetAddress inet)方法加入指定广播方的广播组地址。
(3)使用DatagramPacket(byte[] buf,int length)创建字节数组,接收数据包对象。
(4)使用DatagramSocket类的receive(DatagramPacket 数据包对象)方法接收数据包。
1.数据包套接字与多播套接字
(1)数据包套接字(DatagramSocket类)
java.net包的DatagramSocket类用于创建可以发送和接收数据包的套接字。
DatagramSocket类的构造方法:
new DatagramSocket();
//该构造方法创建DatagramSocket对象,创建数据包套接字。new DatagramSocket(int port);
//该构造方法在创建数据包套接字对象的同时,并绑定了套接字的接口。new DatagramSocket(int port,InetAddress address);
//该构造方法在创建数据包套接字对象的同时,并绑定了套接字的接口和指定的地址。
创建好DatagramSocket对象,绑定了接口,再使用joinGroup()方法(已经使用过构造方法绑定地址的不用使用此方法),就可以发送和接收数据包了。
方法 | 功能描述 | 返回值 |
send(DatagramPacket packet) | 发送指定的数据报到广播组 | void |
receive(DatagramPacket packet) | 从广播组中接收数据报并将其存储在指定的数据包中 | void |
close() | 关闭DatagramSocket对象,关闭套接字 | void |
setSoTimeout(int timeout) | 设置套接字的读取超时时间(以毫秒为单位) | void |
getLocalPort() | 返回此套接字绑定到的本地端口号 | int |
connect(InetAddress address, int port) | 将此套接字连接到指定的远程地址和端口号 | void |
disconnect() | 断开与远程地址的连接 | void |
getInetAddress() | 返回与此套接字连接的远程主机的IP地址 | InetAddress |
getPort() | 返回与此套接字连接的远程主机的端口号 | int |
isClosed() | 检查套接字是否已关闭 | boolean |
isConnected() | 检查套接字是否已连接到远程主机 | boolean |
DatagramSocket()类的receive()方法接收数据时,如果还没有可以接收的数据,正常情况下receive()方法将阻塞,一直等到网络上有数据传来,receive()方法接收到该数据并返回。如果receive()方法没有阻塞,肯定程序出了问题,多数情况下时因为使用了一个被其他程序占用的端口号。
(2)多播套接字(MulticastSocket类)
MulticastSocket extends DatagramSocket
MulticastSocket类是上面的DatagramSocket的子类,这意味着MulticastSocket类都能使用DatagramSocket类的常用方法了,由于该子类有更多的方法供使用,所以在实际编程中,用MuticastSocket创建套接字更多一些。
MulticastSocket类的构造方法:
new MulticastSocket();
//创建一个未绑定到任何本地端口的MulticastSocket对象。new MulticastSocket(int port);
//创建一个绑定到指定本地端口的MulticastSocket对象。
什么情况下使用MulticastSocket类?
(1)多播通信:应用程序需要向多个客户端发送数据,使用MulticastSocket更为合适。
(2)简化的多播管理:MulticastSocket提供了方便的方法,如 joinGroup() 和 leaveGroup(),使得管理多播组变得简单。使用这些方法,你可以轻松地加入或离开多播组,而不需要手动处理组地址和端口。
(3)自动处理:使用 MulticastSocket 时,系统会自动处理多播特性,例如适当的网络路由和数据包的复制,这样你就不需要担心底层的多播实现细节。
(4)适用场景:在局域网内的实时数据传输(如视频流、在线游戏等),那么 MulticastSocket是更好的选择
方法 | 功能描述 | 返回值 |
joinGroup(InetAddress group) | 将套接字加入到指定的多播组,允许套接字开始接收或发送到该组的多播数据 | void |
joinGroup(SocketAddress mcastaddr) | 通过指定的 SocketAddress 来加入多播组 | void |
leaveGroup(InetAddress group) | 将套接字从指定的多播组中移除,停止接收或发送该组的多播数据 | void |
leaveGroup(SocketAddress mcastaddr) | 通过指定的 SocketAddress 来离开多播组 | void |
setTImeToLive(int tti) | 设置数据包的生存时间(TTL),用于控制多播数据包在网络中的跳数。TTL 的值通常在 1 到 255 之间 | void |
getTimeToLive() | 获取当前设置的生存时间(TTL)值 | int |
getLoopbackMode(boolean loopbackMode) | 设置是否允许将发送到多播组的数据包环回到本地的套接字 | void |
getLoopbackMode() | 获取当前的环回模式设置 | boolean |
以上MulticastSocket类的常用方法,并没有写上继承自父类DatagramSocket类的方法,但该子类仍可以使用。子类的这些特有的常用方法使得MulticastSocket能够有效地管理多播组的加入和离开,以及控制多播数据的传输特性。
2.数据报包
数据包(DatagramPackage类)
java.net包的DatagramPacket类用于创建数据包对象,UDP程序中运输数据的包裹。
DatagramPacket类的构造方法:
new DatagramPackage(byte[] buf,int length);
//该构造方法在创建数据包对象的同时,指定了数据包的数据内容和数据长度new DatagramPackage(byte[] buf,int length, InetAddress address,int port);
//该构造方法在创建数据包对象的同时,指定了数据包的数据内容和数据长度,
//还有数据包发送的目标地址和端口
创建数据包对象时,一般使用第二个构造方法,直接绑定UDP地址和端口,省事。
方法 | 功能描述 | 返回值 |
getData() | 返回接收数据包的缓冲区 | byte[] |
getLength() | 返回接收数据包的数据长度 | int |
getAddress() | 返回发送数据包的目标地址 | InetAddress |
getPort() | 返回发送数据包的目标端口 | int |
setData(byte[] buf) | 设置发送数据包的缓冲区 | void |
setLength(int length) | 设置发送数据包的数据长度 | void |
setAddress(InetAddress address) | 设置接收数据包的目标地址 | void |
setPort(int port) | 设置接收数据包的目标端口 | void |
以上方法都是用于调整和设置数据包的发送地址、接口,数据包的大小,字节长度等数据。
3.实操展示
项目设计:实时广播当地的天气,接收方可以为许多当地人的手机,必须实时且同步。
广播组程序:使用MulticastSocket类创建多播套接字,构造方法中绑定接口和加入UDP地址;创建线程,使用Date类,格式化好后,打包到数据包对象中,套接字使用方法发送数据包到指定UDP地址处。
import java.io.IOException;
import java.lang.Thread;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
import java.util.Date;
import java.text.SimpleDateFormat;
public class Sender extends Thread{int port = 9898; //端口InetAddress group; //广播组地址对象MulticastSocket socket; //多播数据包套接字@SuppressWarnings("deprecation")public Sender(){//广播组地址范围:224.0.0.0~239.255.255.255try{group = InetAddress.getByName("224.255.1.1"); //指定广播组地址socket = new MulticastSocket(port); //套接字实例化并绑定接口socket.joinGroup(group); //套接字加入UDP地址,可以向该地址接收或发送消息}catch(UnknownHostException e){e.printStackTrace();}catch(IOException e){e.printStackTrace();}}public void run(){while (true) {DatagramPacket packet;Date date = new Date();SimpleDateFormat sf = new SimpleDateFormat("HH:mm:ss");String message = "["+sf.format(date)+"] 天气预报:当前天气,多云。";byte data[] =message.getBytes();packet = new DatagramPacket(data, data.length, group,port); //创建数据报,实例化,将上述数据存入数据包中,绑定了发送的UDP地址和接口try {socket.send(packet); //向UDP地址发送该数据包System.out.println("Sending: " + message);Thread.sleep(1000);} catch (IOException e) {e.printStackTrace();} catch(InterruptedException e){e.printStackTrace();}}}public static void main(String[] args) {Sender sender = new Sender(); //构造方法解决了套接字的问题,简化了代码sender.start(); //启动线程}}
客户端程序:接收类继承JFrame类,在构造方法中调用超类,创建窗口,实现界面交互(接收或中止接收广播消息),文本域中显示接收到的消息;实现Runnable接口,创建数据包对象,用套接字的方法和while循环不断接收指定UDP地址的广播消息;实现了ActionListener接口,为两个按钮添加监听事件和交互反馈,“接收消息”按钮被点击时,启动线程的start()方法,接收消息。
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;import javax.swing.*;
import java.lang.Runnable;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;@SuppressWarnings("deprecation")
public class Receiver extends JFrame implements Runnable,ActionListener{JButton ince = new JButton("接收消息");JButton stop = new JButton("停止接收");JTextArea inceAr = new JTextArea(10,10);JTextArea inced = new JTextArea(10, 10);Thread thread;boolean getMessage = true; //是否接收广播int port = 9898;InetAddress group;MulticastSocket socket;public Receiver(){super("广播数据报"); //引用超类构造方法,设置窗体标题setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //WindowConstants表示多个窗口的关闭方式inceAr.setForeground(Color.BLUE);JPanel north = new JPanel();north.add(ince); //将按钮添加到面板north上north.add(stop);add(north,BorderLayout.NORTH);JPanel center = new JPanel();center.setLayout(new GridLayout(1,2)); //设置面板布局center.add(inceAr); //将文本域添加到面板上final JScrollPane scrollPane = new JScrollPane();center.add(scrollPane);scrollPane.setViewportView(inced);add(center, BorderLayout.CENTER); //设置面板布局validate(); //重新验证容器中的组件,刷新组件setBounds(100, 50, 640, 380);setVisible(true);ince.addActionListener(this);stop.addActionListener(this);try{group = InetAddress.getByName("224.255.1.1"); //指定广播组地址socket = new MulticastSocket(port); //实例化多播数据包套接字socket.joinGroup(group);} catch (IOException e){e.printStackTrace();}thread = new Thread(this);}@Overridepublic void run(){while (getMessage) {byte data[] = new byte[1024];DatagramPacket packet = new DatagramPacket(data, data.length, group,port);try {socket.receive(packet);String message = new String(packet.getData(),0,packet.getLength());inceAr.setText("正在接收的内容"+message);inced.append(message+"\n");} catch (IOException e) {e.printStackTrace();}}}@Overridepublic void actionPerformed(ActionEvent e) {if(e.getSource()==ince){ince.setBackground(Color.green);stop.setBackground(Color.red);if(!thread.isAlive()){thread = new Thread(this);getMessage = true;}thread.start(); }if(e.getSource()==stop){ince.setBackground(Color.red);stop.setBackground(Color.green);getMessage = false;}}public static void main(String[] args) { new Receiver();}
}
运行结果:
广播组程序:
如图所示,广播组程序向指定的UDP地址每隔一秒就发送一次天气播报。
客户端程序(当广播组程序启动后才能运行):
如图所示,可以有多个客户端,同时且同步的获取到广播组广播的信息,只要它们连接的是同一个接口和UDP地址。
总结
以上就是对UDP程序设计的简单介绍,本文简单介绍了如何搭建UDP程序,该程序在互联网通讯中的应用涉及面十分广泛。如果有疑问或指正的地方,欢迎读者在评论区中留言。