UDP协议程序设计

文章目录


前言

        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()方法(已经使用过构造方法绑定地址的不用使用此方法),就可以发送和接收数据包了。 

DatagramSocket类的常用方法
方法功能描述返回值
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是更好的选择

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地址和端口,省事。 

DatagramPacket类的常用方法
方法功能描述返回值
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.255
        try{
            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);
    }

    

    @Override
    public 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();
            }
             
        }
    }

    @Override
    public 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程序,该程序在互联网通讯中的应用涉及面十分广泛。如果有疑问或指正的地方,欢迎读者在评论区中留言。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喵果森森

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值