1.基本概念:
a.DatagramPacket与DatagramSocket位于java.net包中
b.DatagramPacket表示存放数据的数据报,DatagramSocket表示接受或发送数据报的套接字
c.由这两个类所有构成的网络链接是基于UDP协议,是一种不可靠的协议。
2.DatagramSocket基本用法
DatagramSocket类:创建接收和发送UDP的Socket实例
DatagramSocket():创建实例。通常用于客户端编程,它并没有特定监听的端口,仅仅使用一个临时的。
DatagramSocket(int port):创建实例,并固定监听Port端口的报文。
DatagramSocket(int port, InetAddress localAddr):这是个非常有用的构建器,当一台机器拥有多于一个IP地址的时候,由它创建的实例仅仅接收来自LocalAddr的报文,指定ip地址接受的报文.
receive(DatagramPacket d):接收数据报文到d中。receive方法产生一个“阻塞”。
send(DatagramPacket d):发送报文d到目的地。
setSoTimeout(int timeout):设置超时时间,单位为毫秒。
close():关闭DatagramSocket。在应用程序退出的时候,通常会主动释放资源,关闭Socket,但是由于异常地退出可能造成资源无法回收。所以,应该在程序完成时,主动使用此方法关闭Socket,或在捕获到异常抛出后关闭Sock
注意:在创建DatagramSocket类实例时,如果端口已经被使用,会产生一个SocketException的异常抛出,并导致程序非法终止,这个异常应该注意捕获。
2.DatagramPacket基本用法
DatagramPacket:用于处理报文,将byte数组、目标地址、目标端口等数据包装成报文或者将报文拆卸成byte数组。
DatagramPacket(byte[] buf, int length, InetAddress addr, int port):从buf数组中,取出length长的数据创建数据包对象,目标是addr地址,port端口。
DatagramPacket(byte[] buf, int offset, int length):将数据包中从offset开始、length长的数据装进buf数组。
DatagramPacket(byte[] buf, int length):将数据包中length长的数据装进buf数组。
getData():它从实例中取得报文的byte数组编码。
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port):从buf数组中,取出offset开始的、length长的数据创建数据包对象,目标是addr地址,port端口。
3.代码示例
接受键盘输入后打包,发送该数据包
public class UdpClient { // 定义发送数据报的目的地 public static final int DEST_PORT = 30000; public static final String DEST_IP = "127.0.0.1"; // 定义每个数据报的最大大小为4KB private static final int DATA_LEN = 4096; // 定义接收网络数据的字节数组 byte[] inBuff = new byte[DATA_LEN]; // 以指定的字节数组创建准备接收数据的DatagramPacket对象 private DatagramPacket inPacket = new DatagramPacket(inBuff , inBuff.length); // 定义一个用于发送的DatagramPacket对象 private DatagramPacket outPacket = null; public void init()throws IOException { try( // 创建一个客户端DatagramSocket,使用随机端口 DatagramSocket socket = new DatagramSocket()) { // 初始化发送用的DatagramSocket,它包含一个长度为0的字节数组 outPacket = new DatagramPacket(new byte[0] , 0 , InetAddress.getByName(DEST_IP) , DEST_PORT); // 创建键盘输入流 Scanner scan = new Scanner(System.in); // 不断地读取键盘输入 while(scan.hasNextLine()) { // 将键盘输入的一行字符串转换成字节数组 byte[] buff = scan.nextLine().getBytes(); // 设置发送用的DatagramPacket中的字节数据 outPacket.setData(buff); // 发送数据报 socket.send(outPacket); // 读取Socket中的数据,读到的数据放在inPacket所封装的字节数组中 socket.receive(inPacket); System.out.println(new String(inBuff , 0 , inPacket.getLength())); } } } public static void main(String[] args) throws IOException { new UdpClient().init(); } }
接受端接收UDP数据包
public class UdpServer { public static final int PORT = 30000; // 定义每个数据报的最大大小为4KB private static final int DATA_LEN = 4096; // 定义接收网络数据的字节数组 byte[] inBuff = new byte[DATA_LEN]; // 以指定字节数组创建准备接收数据的DatagramPacket对象 private DatagramPacket inPacket = new DatagramPacket(inBuff , inBuff.length); // 定义一个用于发送的DatagramPacket对象 private DatagramPacket outPacket; // 定义一个字符串数组,服务器端发送该数组的元素 String[] books = new String[] { "疯狂Java讲义", "轻量级Java EE企业应用实战", "疯狂Android讲义", "疯狂Ajax讲义" }; public void init()throws IOException { try( // 创建DatagramSocket对象 DatagramSocket socket = new DatagramSocket(PORT)) { // 采用循环接收数据 for (int i = 0; i < 1000 ; i++ ) { // 读取Socket中的数据,读到的数据放入inPacket封装的数组里 socket.receive(inPacket); // 判断inPacket.getData()和inBuff是否是同一个数组 System.out.println(inBuff == inPacket.getData()); // 将接收到的内容转换成字符串后输出 System.out.println(new String(inBuff , 0 , inPacket.getLength())); // 从字符串数组中取出一个元素作为发送数据 byte[] sendData = books[i % 4].getBytes(); // 以指定的字节数组作为发送数据,以刚接收到的DatagramPacket的 // 源SocketAddress作为目标SocketAddress创建DatagramPacket outPacket = new DatagramPacket(sendData , sendData.length , inPacket.getSocketAddress()); // 发送数据 socket.send(outPacket); } } } public static void main(String[] args) throws IOException { new UdpServer().init(); } }
java点滴之操纵UDP的类:DatagramSocket和DatagramPacket