UDP是無(wú)連接通信協(xié)議,即在數(shù)據(jù)傳輸時(shí)椎眯,數(shù)據(jù)的發(fā)送端和接收端不建立邏輯連接挠将。簡(jiǎn)單來(lái)說(shuō),當(dāng)一臺(tái)計(jì)算機(jī)向另外一臺(tái)計(jì)算機(jī)發(fā)送數(shù)據(jù)時(shí)编整,發(fā)送端不會(huì)確認(rèn)接收端是否存在舔稀,就會(huì)發(fā)出數(shù)據(jù),同樣接收端在收到數(shù)據(jù)時(shí)掌测,也不會(huì)向發(fā)送端反饋是否收到數(shù)據(jù)内贮。
由于使用UDP協(xié)議消耗資源小,通信效率高汞斧,所以通常都會(huì)用于音頻夜郁、視頻和普通數(shù)據(jù)的傳輸例如視頻會(huì)議都使用UDP協(xié)議,因?yàn)檫@種情況即使偶爾丟失一兩個(gè)數(shù)據(jù)包粘勒,也不會(huì)對(duì)接收結(jié)果產(chǎn)生太大影響竞端。
但是在使用UDP協(xié)議傳送數(shù)據(jù)時(shí),由于UDP的面向無(wú)連接性庙睡,不能保證數(shù)據(jù)的完整性事富,因此在傳輸重要數(shù)據(jù)時(shí)不建議使用UDP協(xié)議技俐。UDP的交換過(guò)程如下圖所示。
前面介紹了UDP是一種面向無(wú)連接的協(xié)議统台,因此雕擂,在通信時(shí)發(fā)送端和接收端不用建立連接。UDP通信的過(guò)程就像是貨運(yùn)公司在兩個(gè)碼頭間發(fā)送貨物一樣贱勃。在碼頭發(fā)送和接收貨物時(shí)都需要使用集裝箱來(lái)裝載貨物井赌,UDP通信也是一樣,發(fā)送和接收的數(shù)據(jù)也需要使用“集裝箱”進(jìn)行打包贵扰,為此JDK中提供了一個(gè)DatagramPacket類(lèi)仇穗,該類(lèi)的實(shí)例對(duì)象就相當(dāng)于一個(gè)集裝箱,用于封裝UDP通信中發(fā)送或者接收的數(shù)據(jù)拔鹰。
示例():
發(fā)送端:
package cn.itcast.demo1;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/*
*? 實(shí)現(xiàn)UDP協(xié)議的發(fā)送端:
*? ? 實(shí)現(xiàn)封裝數(shù)據(jù)的類(lèi) java.net.DatagramPacket? 將你的數(shù)據(jù)包裝 *? ? 實(shí)現(xiàn)數(shù)據(jù)傳輸?shù)念?lèi) java.net.DatagramSocket? 將數(shù)據(jù)包發(fā)出去*
*? 實(shí)現(xiàn)步驟:
*? ? 1. 創(chuàng)建DatagramPacket對(duì)象,封裝數(shù)據(jù), 接收的地址和端口 *? ? 2. 創(chuàng)建DatagramSocket
*? ? 3. 調(diào)用DatagramSocket類(lèi)方法send,發(fā)送數(shù)據(jù)包 *? ? 4. 關(guān)閉資源*
*? ? DatagramPacket構(gòu)造方法:
*? ? ? DatagramPacket(byte[] buf, int length, InetAddress address, int port)
*
*? ? DatagramSocket構(gòu)造方法:
*? ? ? DatagramSocket()空參數(shù) *? ? ? 方法: send(DatagramPacket d)
*
*/
public class UDPSend {
public static void main(String[] args)throws IOException{
//創(chuàng)建數(shù)據(jù)包對(duì)象,封裝要發(fā)送的數(shù)據(jù),接收端IP,端口
? ? ? byte[] date ="你好UDP".getBytes();
? ? ? //創(chuàng)建InetAddress對(duì)象,封裝自己的IP地址
? ? ? InetAddress inet = InetAddress.getByName("127.0.0.1");
? ? ? DatagramPacket dp =new DatagramPacket(date, date.length, inet,6000);
? ? ? //創(chuàng)建DatagramSocket對(duì)象,數(shù)據(jù)包的發(fā)送和接收對(duì)象
? ? ? DatagramSocket ds =new DatagramSocket();
? ? ? //調(diào)用ds對(duì)象的方法send,發(fā)送數(shù)據(jù)包
? ? ? ds.send(dp);
? ? ? //關(guān)閉資源
? ? ? ds.close();
? }
}
接收端:
package com.example.mbenben.newstudy;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/*
*? 實(shí)現(xiàn)UDP接收端 *? ? 實(shí)現(xiàn)封裝數(shù)據(jù)包 java.net.DatagramPacket 將數(shù)據(jù)接收 *? ? 實(shí)現(xiàn)輸出傳輸? ? java.net.DatagramSocket 接收數(shù)據(jù)包*
*? 實(shí)現(xiàn)步驟:
*? ? 1. 創(chuàng)建DatagramSocket對(duì)象,綁定端口號(hào) *? ? ? ? 要和發(fā)送端端口號(hào)一致 *? ? 2. 創(chuàng)建字節(jié)數(shù)組,接收發(fā)來(lái)的數(shù)據(jù) *? ? 3. 創(chuàng)建數(shù)據(jù)包對(duì)象DatagramPacket
*? ? 4. 調(diào)用DatagramSocket對(duì)象方法 *? ? ? ? receive(DatagramPacket dp)接收數(shù)據(jù),數(shù)據(jù)放在數(shù)據(jù)包中 *? ? 5. 拆包 *? ? ? ? ? 發(fā)送的IP地址 *? ? ? ? ? ? 數(shù)據(jù)包對(duì)象DatagramPacket方法getAddress()獲取的是發(fā)送端的IP地址對(duì)象 *? ? ? ? ? ? 返回值是InetAddress對(duì)象 *? ? ? ? ? 接收到的字節(jié)個(gè)數(shù) *? ? ? ? ? ? 數(shù)據(jù)包對(duì)象DatagramPacket方法getLength()
*? ? ? ? ? 發(fā)送方的端口號(hào) *? ? ? ? ? ? 數(shù)據(jù)包對(duì)象DatagramPacket方法 getPort()發(fā)送端口 *? ? 6. 關(guān)閉資源*/
public class UDPReceive {
public static void main(String[] args)throws IOException {
//創(chuàng)建數(shù)據(jù)包傳輸對(duì)象DatagramSocket 綁定端口號(hào)
? ? ? DatagramSocket ds =new DatagramSocket(6000);
? ? ? //創(chuàng)建字節(jié)數(shù)組
? ? ? byte[] data =new byte[1024];
? ? ? //創(chuàng)建數(shù)據(jù)包對(duì)象,傳遞字節(jié)數(shù)組
? ? ? DatagramPacket dp =new DatagramPacket(data, data.length);
? ? ? //調(diào)用ds對(duì)象的方法receive傳遞數(shù)據(jù)包
? ? ? ds.receive(dp);
? ? ? //獲取發(fā)送端的IP地址對(duì)象
? ? ? String ip=dp.getAddress().getHostAddress();
? ? ? //獲取發(fā)送的端口號(hào)
? ? ? int port = dp.getPort();
? ? ? //獲取接收到的字節(jié)個(gè)數(shù)
? ? ? int length = dp.getLength();
? ? ? System.out.println(new String(data,0,length)+"..."+ip+":"+port);
? ? ? ds.close();
? }
}