Java 网络编程:(七)UDP网络编程

一、UDP协议

  UDP(User Datagram Protocol,用户数据报协议):是一个无连接的传输层协议、提供面向事务的简单不可靠的信息传送服务,类似于短信。

  UDP协议是一种面向非连接的协议,面向非连接指的是在正式通信前不必与对方先建立连接,不管对方状态就直接发送,至于对方是否可以接收到这些数据内容,UDP协议无法控制,因此说,UDP协议是一种不可靠的协议。无连接的好处就是快,省内存空间和流量,因为维护连接需要创建大量的数据结构。UDP会尽最大努力交付数据,但不保证可靠交付,没有TCP的确认机制、重传机制,如果因为网络原因没有传送到对端,UDP也不会给应用层返回错误信息。

  UDP协议是面向数据报文的信息传送服务。UDP在发送端没有缓冲区,对于应用层交付下来的报文在添加了首部之后就直接交付于ip层,不会进行合并,也不会进行拆分,而是一次交付一个完整的报文。比如我们要发送100个字节的报文,我们调用一次send()方法就会发送100字节,接收方也需要用receive()方法一次性接收100字节,不能使用循环每次获取10个字节,获取十次这样的做法。

  UDP协议没有拥塞控制,所以当网络出现的拥塞不会导致主机发送数据的速率降低。虽然UDP的接收端有缓冲区,但是这个缓冲区只负责接收,并不会保证UDP报文的到达顺序是否和发送的顺序一致。因为网络传输的时候,由于网络拥塞的存在是很大的可能导致先发的报文比后发的报文晚到达。如果此时缓冲区满了,后面到达的报文将直接被丢弃。这个对实时应用来说很重要,比如:视频通话、直播等应用。

  因此UDP适用于一次只传送少量数据、对可靠性要求不高的应用环境,数据报大小限制在64K以下。

二、UDP网络通信概述

  1、DatagramSocket DatagramPacket 实现了基于 UDP 协议网络程序。

  2、UDP 数据报通过数据报套接字 DatagramSocket 发送和接收, 系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达

  3、DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。

  4、UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接。 如同发快递包裹一样。

   基于UDP协议的网络编程仍然需要在通信实例的两端各建立一个Socket,但这两个Socket之间并没有虚拟链路,这两个Socket只是发送、接收数据报的对象,Java提供了DatagramSocket对象作为基于UDP协议的Socket,使用DatagramPacket代表DatagramSocket发送、接收的数据报。

三、DatagramSocket 类的常用方法

public DatagramSocket(int port)创建数据报套接字并将其绑定到本地主机上的指定端口。 套接字将被绑定到通配符地址, IP 地址由内核来选择。
public DatagramSocket(int port,InetAddress laddr)创建数据报套接字, 将其绑定到指定的本地地址。
本地端口必须在 0 到 65535 之间(包括两者) 。 如果 IP 地址为 0.0.0.0, 套接字将被绑定到通配符地址, IP 地址由内核选择。
public void close()关闭此数据报套接字。
public void send(DatagramPacket p)从此套接字发送数据报包。 DatagramPacket 包含的信息指示:将要发送的数据、 其长度、 远程主机的 IP 地址和远程主机的端口号。
public void receive(DatagramPacket p)从此套接字接收数据报包。 当此方法返回时, DatagramPacket的缓冲区填充了接收的数据。 数据报包也包含发送方的 IP 地址和发送方机器上的端口号。
此方法在接收到数据报前一直阻塞。 数据报包对象的 length 字段包含所接收信息的长度。 如果信息比包的长度长, 该信息将被截短。
public InetAddress getLocalAddress()获取套接字绑定的本地地址。
public int getLocalPort()返回此套接字绑定的本地主机上的端口号。
public InetAddress getInetAddress()返回此套接字连接的地址。 如果套接字未连接, 则返回 null。
public int getPort()返回此套接字的端口。 如果套接字未连接, 则返回 -1。

  

四、Datagrampacket 类的常用方法

public DatagramPacket(byte[] buf,int length)构造 DatagramPacket, 用来接收长度为 length 的数据包。 length 参数必须小于等于 buf.length。
public DatagramPacket(byte[] buf,int length,InetAddress address,int port)构造数据报包, 用来将长度为 length 的包发送到指定主机上的指定端口号。 length参数必须小于等于 buf.length。
public InetAddress getAddress()返回某台机器的 IP 地址, 此数据报将要发往该机器或者是从该机器接收到的。
public int getPort()返回某台远程主机的端口号, 此数据报将要发往该主机或者是从该主机接收到的。
public byte[] getData()返回数据缓冲区。 接收到的或将要发送的数据从缓冲区中的偏移量 offset 处开始, 持续 length 长度。
public int getLength()返回将要发送或接收到的数据的长度。

  

五、UDP 网络通信

  流程

    (1)DatagramSocketDatagramPacket
    (2)建立发送端,接收端
    (3)建立数据包
    (4)调用Socket的发送、 接收方法
    (5)关闭Socket

  注意:发送端与接收端是两个独立的运行程序,与 TCP 有所不同,TCP需要先启动服务器再启动客户端。  

六、案例一

  1、发送端

     步骤流程:

     (1)建立发送端的DatagramSocket,需要指定本端的端口号

     (2)建立数据包DatagramPacket

          ① 数据    

          ② 接收端的IP地址

          ③ 接收端的端口号

     (3)调用DatagramSocket的发送方法

     (4)关闭DatagramSocket

     示例代码:

 1 import java.net.DatagramPacket;
 2 import java.net.DatagramSocket;
 3 import java.net.InetAddress;
 4 import java.util.ArrayList;
 5 
 6 public class Send {
 7 
 8     public static void main(String[] args)throws Exception {
 9         //1、建立发送端的DatagramSocket
10         DatagramSocket ds = new DatagramSocket();
11         
12         //要发送的数据
13         ArrayList<String> all = new ArrayList<String>();
14         all.add("Hello");
15         all.add("World");
16         all.add("Hello");
17         all.add("Java");
18         
19         //接收方的IP地址
20         InetAddress ip = InetAddress.getByName("127.0.0.1");
21         //接收方的监听端口号
22         int port = 9999;
23          //发送多个数据报
24         for (int i = 0; i < all.size(); i++) {
25             //2、建立数据包DatagramPacket
26             byte[] data = all.get(i).getBytes();
27             DatagramPacket dp = new DatagramPacket(data, data.length, ip, port);
28             //3、调用Socket的发送方法
29             ds.send(dp);
30         }
31         
32         //4、关闭Socket
33         ds.close();
34     }
35 }

  2、接收端

     步骤流程:

      (1)建立接收端的DatagramSocket,需要指定本端的IP地址和端口号

      (2)建立数据包DatagramPacket

           需要指定装数据的数组

      (3)调用Socket的接收方法

      (4)拆封数据

      (5)关闭Socket

    实例代码:

 1 import java.net.DatagramPacket;
 2 import java.net.DatagramSocket;
 3 
 4 public class Receive {
 5 
 6     public static void main(String[] args) throws Exception {
 7         //1、建立接收端的DatagramSocket,需要指定本端的监听端口号
 8         DatagramSocket ds = new DatagramSocket(9999);
 9         
10         //一直监听数据
11         while(true){
12            //2、建立数据包DatagramPacket
13             byte[] buffer = new byte[1024*64];
14             DatagramPacket dp = new DatagramPacket(buffer , buffer.length);
15             
16             //3、调用Socket的接收方法
17             ds.receive(dp);
18             
19             //4、拆封数据
20             String str = new String(buffer,0,dp.getLength());
21             System.out.println(str);
22         }
23     }
24 }

七、案例二

   发送方:

 1     @Test
 2     public void sender() throws IOException {
 3 
 4         DatagramSocket socket = new DatagramSocket();
 5 
 6 
 7         String str = "我是UDP方式发送的导弹";
 8         byte[] data = str.getBytes();
 9         InetAddress inet = InetAddress.getLocalHost();
10         DatagramPacket packet = new DatagramPacket(data,0,data.length,inet,9090);
11 
12         socket.send(packet);
13 
14         socket.close();
15 
16     }


  接收方:

 1     @Test
 2     public void receiver() throws IOException {
 3 
 4         DatagramSocket socket = new DatagramSocket(9090);
 5 
 6         byte[] buffer = new byte[100];
 7         DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);
 8 
 9         socket.receive(packet);
10 
11         System.out.println(new String(packet.getData(),0,packet.getLength()));
12 
13         socket.close();
14     }
原文地址:https://www.cnblogs.com/niujifei/p/14878945.html