学科分类
目录
Java基础

UDP网络程序

前面两个小节讲解了DatagramPacket和DatagramSocket的相关知识,接下来通过一个案例来学习一下它们的具体用法。要实现UDP通信需要创建一个发送端程序和一个接收端程序,很明显,在通信时只有接收端程序先运行,才能避免因发送端发送的数据无法接收,而造成数据丢失。因此,首先需要来完成接收端程序的编写,如文件1所示。

文件1 UDPReceiver.java

 1    import java.net.*;
 2    // 接收端程序
 3    public class UDPReceiver {
 4        public static void main(String[] args) throws Exception {
 5            // 定义一个指定端口号为8900的接收端DatagramSocket对象
 6            DatagramSocket server = new DatagramSocket(8900);
 7            // 定义一个长度为1024的字节数组,用于接收数据
 8            byte[] buf = new byte[1024];
 9            // 定义一个DatagramPacket数据报对象,用于封装接收的数据
 10            DatagramPacket packet = new DatagramPacket(buf, buf.length);
 11            System.out.println("等待接收数据...");
 12            while (true){
 13                // 等待接收数据报数据,在没有接收到数据之前会处于阻塞状态
 14                server.receive(packet); 
 15                // 调用DatagramPacket的方法获得接收到的信息,并转换为字符串形式
 16                String str = new String(packet.getData(), 
 17                                              0, packet.getLength());
 18                System.out.println(packet.getAddress()+ ":" 
 19                                        + packet.getPort()+"发送消息:"+str);
 20            }
 21        }
 22    }

运行结果如图1所示。

图1 运行结果

文件1中,创建了一个UDP接收端程序,用来接收数据。在创建DatagramSocket对象时,指定其监听的端口号为8900,这样发送端就能通过这个端口号与接收端程序进行通信。之后创建DatagramPacket对象时传入一个大小为1024个字节的数组用来接收数据,当调用该对象的receive(DatagramPacket p)方法接收到数据以后,数据会填充到DatagramPacket中,通过DatagramPacket的相关方法可以获取接收到的数据信息。

从图1可以看到,程序运行后一直处于停滞状态等待接收数据,但一直没有输出获取的主机信息,这是因为DatagramSocket的receive()方法在运行时会发生阻塞,只有接收到发送端程序发送的数据时,该方法才会结束这种阻塞状态,程序才能继续向下执行。

实现了接收端程序之后,接下来还需要编写一个发送端的程序,如文件2所示。

文件2 UDPSender.java

 1    import java.net.*;
 2    // 发送端程序
 3    public class UDPSender {
 4        public static void main(String[] args) throws Exception {
 5            // 定义一个指定端口号为3000的发送端DatagramSocket对象
 6            DatagramSocket client = new DatagramSocket(3000);
 7            // 定义要发送的数据
 8            String str = "hello world"; 
 9            // 定义一个DatagramPacket数据报对象,封装发送端信息以及发送地址
 10            DatagramPacket packet = new DatagramPacket(str.getBytes(),
 11                                    str.getBytes().length,
 12                                    InetAddress.getByName("localhost"),8900);
 13            System.out.println("开始发送信息...");
 14            client.send(packet); // 发送数据
 15            client.close();       // 释放资源
 16        }
 17    }

运行结果如图2所示。

图2 运行结果

文件2创建了一个UDP发送端程序,用来发送数据。在创建DatagramPacket对象时需要指定目标IP地址和端口号,而且端口号必须要和接收端指定的端口号一致,这样调用DatagramSocket的send()方法才能将数据发送到对应的接收端。

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

图3 运行结果

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

注意:

UDP程序在发送数据时,是一次性全部封装到DatagramPacket数据报中进行统一发送的,然而DatagramPacket数据报一次性允许封装的数据量是有限度的,理论最大数量是65507字节(即IP数据报的最大限制65535字节减去IP首部的20字节和UDP首部的8字节),但实际上总是比这要少的多,在许多平台下,实际的最大限制是8192字节(8K),甚至低于8K。因此,UDP协议中如果发送端一次性发送超过8K的数据报,就需要特别注意,大多时候,这种更大的包会被简单的截取到8K数据。同时,从文件11-2可以看出,接收DatagramPacket数据报的缓存区大小设置为了1024字节大小,如果发送端的数据过大,显然也会出现数据丢失的情况,所以这种情况下一般会将接收端DatagramPacket数据报的缓存区大小设置为UDP数据理论最大限制65507字节,但本程序数据量较小所以将缓冲区设置为1024字节大小。

点击此处
隐藏目录