网络编程之UDP

什么是UDP通信

面向无连接、不可靠、速度快、将数据封装成包传输,数据包最大64k

UPD通信的过程就像是货运公司在两个码头之间发送货物一样,在码头发送和接收货物时都需要使用集装箱来装载货物。UPD通信也一样,发送和接收的数据也需要使用 " 集装箱 " 进行打包,为此JDK中提供了一个DatagramPacket类,该类的实例对象就相当于一个集装箱,用于封装UPD通信中发送或者接收的数据。

DatagramPacket(byte[] buf,int length)

使用该构造方法在创建DatagramPacket对象时,指定了封装数据的字节数组和数据的大小,没有指定IP地址和端口号。很明显,这样的对象只能用于接收端,不能用于发送端。因为发送端一定要明确指出数据的目的地(IP地址和端口号),而接收端不需要明确知道数据的来源,只需要接收到数据即可。

DatagramPacket(byte[] buf,int length,InetAddress address,int port)

使用该构造方法在创建DatagramPacket对象时,不仅指定了封装数据的字节数组和数据的大小,还指定了数据包的目标IP地址(addr)和端口号(port)。该对象通常用于发送端,因为在发送数据时必须指定接收端的IP地址和端口号,就好像发送货物的集装箱上面必须标明接收人的地址一样。

 

 

上面讲到DatagramPacket数据包的作用就如同 " 集装箱 ",可以将发送端或者接收端的数据封装起来。然而运输货物只有 " 集装箱 " 是不够的,还需要 " 码头 "。同理,在程序中,要实现通信,只有DatagramPacket数据包也是不行的,它也需要一个 " 码头 "。为此,JDK提供了一个DatagramSocket类,该类的作用就类似于 " 码头 ",使用这个类的实例对象就可以发送和接收DatagramPacket的数据包。

DatagramSocket(int port)

该构造方法即可用于创建接收端的DatagramSocket对象,又可以创建发送端的DatagramSocket对象,在创建接收端的DatagramSocket对象时,必须要指定一个端口号,这样就可以监听指定的端口。

 

 

 UDP网络程序

上面讲解了DatagramPacket和DatagramSocket的相关知识,接下来通过一个案例来学习一下他们在程序中的具体用法。要实现UDP通信需要创建一个发送端程序和一个接收端程序,很明显,在通信时只有接收端程序先运行,才能避免发送端发送数据时找不到接收端而造成的数据丢失问题。

建立UDP主机A(接收方)编程模型:

  1. 创建DatagramSocket类型的对象,并提供端口号
  2. 创建DatagramPacket类型的对象,用于接收发送来的数据
  3. 使用上述对象接收数据的内容,使用recieve()方法
  4. 关闭相关资源

public class Example01 {
    public static void main(String[] args) throws Exception {
        //创建一个长度为1024的字节数组,用于放数据
        byte[] by = new byte[1024];
        //定义一个DatagramSocket对象,监听的端口号为8899;
        DatagramSocket ds = new DatagramSocket(8899);
        //定义一个DatagramPacket对象,用于接收数据
        DatagramPacket dp = new DatagramPacket(by, by.length);
        //等待接收数据,没有数组则会阻塞
        ds.receive(dp);
        //获取接收到的数据,包括数据内容、长度、发送端和IP地址和端口号
        String str = new String(dp.getData(),0,dp.getLength()) + " from "+dp.getAddress().getHostAddress()+":"+dp.getPort();
        System.out.println(str);     //打印接收到的信息
        //关闭资源
        ds.close();
    }
}

运行接收端程序后,程序一直处于停滞状态,这是因为DatagramSocket的receive()方法在运行时会发生阻塞,只有接收到发送端程序发送的数据时,该方法才会结束这种阻塞状态,程序才会继续向下执行。

建立UDP主机B(发送方)编程模型:

  1. 创建DatagramSocket类型的对象
  2. 创建DatagramPacket类型的对象,并提供端口号和IP地址
  3. 使用上述的对象发送数据内容,使用send()方法
  4. 关闭相关资源

public class Example02 {
    public static void main(String[] args) throws Exception {
        //创建一个DatagramSocket对象,指定本地端口号
        DatagramSocket ds = new DatagramSocket(8520);
        //要发送的数据
        byte[] str="嘿嘿嘿".getBytes();
        //创建一个要发送的数据,指定数据、IP地址、端口号
        DatagramPacket dp = new DatagramPacket(str, str.length, InetAddress.getByName("localhost"), 8899);
        System.out.println("发送数据!");
        //发送数据
        ds.send(dp);
        //关闭资源
        ds.close();
    }
}

在接收端程序阻塞的状态下,运行发送端程序,接收端程序就会收到发送端发送的数据而结束阻塞状态,并打印接收到的数据。

需要注意的是,在创建发送端的DatagramSocket对象时,可以不指定端口号,程序中指定端口号的目的是为了每次运行时接收端的getPort()方法的返回值都是一直的,否则发送端的端口号由系统自动分配,接收端的getPort()方法的返回值每次都不同。

posted @ 2019-10-15 21:24  tunan96  阅读(185)  评论(0编辑  收藏  举报