一、基本认识
1、什么是UDP协议?
UDP协议,也就是用户数据报协议(User Datagram Protocol),是一个简单的面向数据报的传输层协议。只在IP协议上增加了很少一点的功能,就是复用和分用,以及差错检测的功能。
特点我们可以整理总结一下:
(1)无连接:也就是说发送之前不需要建立连接,直接发送就可以,和TCP协议相比就减少了三次握手四次挥手等时间的消耗。
(2)不可靠交付:也就是说,我们只管发送数据,对方收没收到不需要去管。
(3)面向报文:只进行简单的添加首部数据,就直接封装成IP包发送了。
(4)支持多对多:这里表示的就是单播多播广播机制。
(5)没有拥塞控制
2、数据格式
在上面我们知道,UDP协议包只在I协议上增加了很少一点的功能,就是复用和分用,以及差错检测的功能。那添加的这些数据是什么样子的呢?
UDP协议分为首部字段和数据字段,其中首部字段只占用8个字节,分别是个占用两个字节的源端口、目的端口、长度和检验和。
我们在这里对添加的数据字段分别进行一个解释说明:
(1)伪首部:伪首部其实是在校验和的时候添加的,起到一个辅助运算的作用。并不是真正的首部。校验和是为了检查报文中的数据是否有差错,如果没有差错,那么校验和之后的结果应该是1.
(2)源端口:源端口,这是为了收到对方的回音才使用的。
(3)目的端口:也就是UDP数据包的发送目的地。
(4)长度:数据长度
(5)检验和:检查是否数据出现了差错,如果有差错,那就丢弃。
3、UDP协议能做什么?
在UDP协议之上的协议相信我们都听过,比如说DNS、TFTP、SNMP等等,这些协议在网络通信中非常的实用也非常的重要。而且像视频、音频、和一些无关紧要的数据都可以使用他来发送,省时省力。
有一个非常重要的例子,那就是我们的微信聊天的场景,他就是采用的UDP协议,因为UDP协议是不可靠协议,你只管发送就好了,不管对方是否收到信息。对方有时间就会看到这条消息。
4、通信方式
在java中,UDP通信方式主要有三种:单播、多播和广播。
1)单播:每次只有两个主机在通信。
在IPv4网络中,0.0.0.0到223.255.255.255属于单播地址。就好比说你在大街上叫你女朋友名字,那么就只有你女朋友回头。
(2)广播:当前主机和当前局域网下所有的主机通信
广播肯定都是限制在局域网中的,因为你要是朝着整个互联网广播一条消息,那实在是太麻烦了,而且很多人广播的时候会造成网络堵塞,因此只限定在局域网中。这种方式也很好理解,就好比你在大街上叫了一声“美女帅哥”,那么周围(局域网)所有的人都会回头。
他的地址一般都是255.255.255.255。另外ipv6不支持广播。
(3)多播:当前主机和当前局域网下一部分主机通信
多播也很好理解,就比如你在大街上只喊了一句美女,没有喊帅哥,那么就只有美女回头,帅哥不会回头。组播的地址就比较麻烦一点了。因为你可以把你要通信的地址汇聚到一块形成一个多播组。但是有些地址是官方已经限定好了的,你就没法使用,这叫做永久组。还有一些没被使用的地址就组成了临时组。
其中永久的组播地址:224.0.0.0-224.0.0.2。而剩下的就是临时组了:224.0.1.0~224.0.1.255是公用组播地址
下面我们着重使用代码来实现一下这三种通信方式:
二、代码实现
1、单播案例
单播案例很简单,在这里我们假设,你在大街上叫你女朋友名字,然后你女朋友回头答复了你一句。
首先看一下服务端:代表女朋友:
class UDPServer{ public static void main(String[] args)throws IOException{ //新建一个socket绑定8888端口 DatagramSocket server = new DatagramSocket(8888); //接收消息 byte[] recvBuf = new byte[100]; DatagramPacket recvPacket = new DatagramPacket(recvBuf , recvBuf.length); server.receive(recvPacket); String recvStr = new String(recvPacket.getData() , 0 , recvPacket.getLength()); System.out.println("来自男朋友的呼唤;" + recvStr); //发送消息:根据接受的port确定男朋友在哪 int port = recvPacket.getPort(); InetAddress addr = recvPacket.getAddress(); String sendStr = "不想回复你,只想买衣服"; byte[] sendBuf; sendBuf = sendStr.getBytes(); DatagramPacket sendPacket = new DatagramPacket(sendBuf,sendBuf.length ,addr,port); server.send(sendPacket); server.close(); } }
然后就是客户端了
class UDPClient{ public static void main(String[] args)throws IOException{ DatagramSocket client = new DatagramSocket(); //发送数据 String sendStr = "Hello!王xx"; byte[] sendBuf; sendBuf = sendStr.getBytes(); InetAddress addr = InetAddress.getByName("127.0.0.1"); int port = 8888; DatagramPacket sendPacket = new DatagramPacket(sendBuf ,sendBuf.length , addr , port); client.send(sendPacket); //接受数据 byte[] recvBuf = new byte[100]; DatagramPacket recvPacket = new DatagramPacket(recvBuf , recvBuf.length); client.receive(recvPacket); String recvStr = new String(recvPacket.getData() , 0 ,recvPacket.getLength()); System.out.println("收到女朋友的回复:" + recvStr); client.close(); } }
代码很简单,你运行一下就能体会到,在这里就不显示结果了。在这里我们会发现里面主要涉及到了两个类DatagramSocket和DatagramPacket。分别表示socket和数据包。这一点和广播涉及到的类是一样的。
2、广播
在大街上,你突然喊了一句,帅哥美女们,于是乎都回头了。
首先是服务端:帅哥美女们
class UDPServer{ public static void main(String[] args) { int port = 9999;//开启监听的端口 DatagramSocket ds = null; DatagramPacket dp = null; byte[] buf = new byte[1024];//存储发来的消息 StringBuffer sbuf = new StringBuffer(); try { //绑定端口的 ds = new DatagramSocket(port); dp = new DatagramPacket(buf, buf.length); System.out.println("街上的帅哥美女们都准备好了:"); ds.receive(dp); ds.close(); int i; for(i=0;i<1024;i++){ if(buf[i] == 0){ break; } sbuf.append((char) buf[i]); } System.out.println("听到街上有人说:" + sbuf.toString()); } catch (Exception e) { e.printStackTrace(); } } }
然后就是客户端:
class UDPClient{ public static void main(String[] args)throws IOException{ String host = "255.255.255.255";//广播地址 int port = 9999;//广播的目的端口 String message = "hello girl and boy";//用于发送的字符串 try{ InetAddress adds = InetAddress.getByName(host); DatagramSocket ds = new DatagramSocket(); DatagramPacket dp = new DatagramPacket(message.getBytes(),message.length(), adds, port); ds.send(dp); ds.close(); } catch (Exception e) { e.printStackTrace(); } } }
完整的代码都在这了,对于结果自己运行一下吧。
3、多播
在大街上,你突然喊了一句美女,于是乎街上的美女们就都回头了,但是帅哥却不会。
首先是服务端:美女
class UDPServer { private static MulticastSocket ds; static String multicastHost = "239.0.1.255"; static InetAddress receiveAddress; public static void main(String[] args) throws IOException { ds = new MulticastSocket(8899); // 也就是只接受239.0.1.255这个地址的人发来的消息 receiveAddress = InetAddress.getByName(multicastHost); // 加入多播组 ds.joinGroup(receiveAddress); //在线程里面处理信息 new Thread() { public void run() { byte buf[] = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf, 1024); while (true) { try { System.out.println("美女(没有帅哥)准备好了:"); ds.receive(dp); String receiveMsg=new String(buf, 0, dp.getLength()); System.out.println("美女听到街上有人喊:" + receiveMsg); } catch (Exception e) { e.printStackTrace(); } } } }.start(); } }
然后是客户端
class UDPClient{ public static void main(String[] args) throws IOException{ MulticastSocket ms=null; DatagramPacket dataPacket = null; ms = new MulticastSocket(); ms.setTimeToLive(32); //将本机的IP地址放到数据包里 byte[] data = "街上的美女们".getBytes(); InetAddress address = InetAddress.getByName("239.0.1.255"); dataPacket = new DatagramPacket(data, data.length, address,8899); ms.send(dataPacket); ms.close(); } }
可能你已经发现了,DatagramSocket已经变成了MulticastSocket,说明多播有自己的实现机制。如果你想进一步了解,可以深入其源码看看。
OK。java中UDP编程基本上就是这三种方式,基本案例在此,你可以根据自己的需要变形。