UDP協議
特點:
1.面向無連接的傳輸層協議
(1)UDP協議在傳輸報文之前不需要在通信雙方建立連接 因此減少了協議開銷與傳輸延遲
(2)UDP對報文除了提供校驗和之外幾乎沒有提供其他的保證數據傳輸可靠性的措施
(3)如果UDP協議檢查出收到的分分組出錯 它就丟棄這個分組 即不確認也不通知發送端和要求重發
2. 面向報文的傳輸層協議
(1)UDP協議對於應用程序提交的報文,在添加了UDP頭部,構成一個TPDU之後就向下提交給IP層
(2)UDP協議對應用程序提交的報文既不合並也不拆分 而是保留原來的報文長度和格式。接收端將發送端提交發送的報文原封不動的提交給接收端應用程序。所以使用UDP協議時 應用程序要選擇合適長度的報文
(3)如果應用程序提交的報文太短 則協議開銷相對較大 如果太長 則UDP協議向IP層提交的TPDU可能在IP層被分片 這會降低協議效率
UDP是適合實時語音與視頻傳輸的傳輸層協議
UDP接收端:udpsender
public static void main(String[] args) {
DatagramSocket socket=null;
try {
//通過DatagramSocket對象創建UDP
socket=new DatagramSocket();
//確定數據源 分裝成數據包 指定數據源大小 和 接收端的ip 端口
byte[] buf="UDP bao wen lai le".getBytes();
DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.254"),20000);
//通過socket套接字將數據包發送出去 通過send方法
socket.send(dp);
//關閉資源
socket.close();
} catch (SocketException e) {
e.printStackTrace();
}
catch (UnknownHostException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
//關閉資源
socket.close();
}
UDP接收端:udpreceiverpublic static void main(String[] args) {
DatagramSocket socket=null;
try {
//通過DatagramSocket對象創建UDP 監控端點
socket=new DatagramSocket(20000);
//定義數據包 來存儲接受的數據
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
//socket用receive方法將數據存入數據包中
socket.receive(dp);
//通過數據包的方法獲取數據包中的數據
String ip=dp.getAddress().getHostAddress();
String data=new String(dp.getData(),0,dp.getLength());
int port=dp.getPort();
System.out.println("ip: "+ip+" data: "+data+" port: "+port);
//關閉資源
socket.close();
} catch (SocketException e) {
e.printStackTrace();
}
catch (UnknownHostException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
//關閉資源
socket.close();
}
編譯然後運行
注意:兩個編譯完成後 先運行UDPReciver 然後在運行UDPSender
運行出現Could not find or load main class。 這個參考:https://stackoverflow.com/questions/18093928/what-does-could-not-find-or-load-main-class-mean
看到運行結果可能很好奇47242 和50117是什麼? 它們是發送方的端口。你也可以指定發送方的端口。
socket=new DatagramSocket(8888);
在發送方里是指定發送端口 在接收方是監聽端口。
如果不指定端口發送 時 爲什麼發送的端口不一樣 ? 即爲什麼都是47242 而變成50117? 因爲運行結束後這個端口還在被佔用着所以程序需要另外一個端口。
聊天:
public class ChatDemo {
public static void main(String[] args) throws Exception{
DatagramSocket send=new DatagramSocket();
DatagramSocket rece=new DatagramSocket(20000);
new Thread(new Send(send)).start();
new Thread(new Send(rece)).start();
}
}
接收方:
public class Recive implements Runnable{
private DatagramSocket ds;
private Recive(DatagramSocket ds){
this.ds=ds;
}
public void run() {
try{
while(true){
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
ds.receive(dp);//阻塞方法 所以上面的while不會死循環
String ip=dp.getAddress().getHostAddress();
String data=new String(dp.getData(),0,dp.getLength());
int port=dp.getPort();
System.out.println("ip: "+ip+" data: "+data+" port: "+port);
}
}catch(Exception e){
throw new RuntimeException("接收失敗");
}
}
}
發送方:
public class Send implements Runnable{
private DatagramSocket ds;
public Send(DatagramSocket ds){
this.ds=ds;
}
public void run() {
BufferedReader buff=new BufferedReader(new InputStreamReader(System.in));
String line=null;
try {
while((line=buff.readLine())!=null){
if("886".equals(line))
break;
byte[] buf=line.getBytes();//下面ip的最後以爲255廣播 給該局域網
DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.xx.255"),20000);
ds.send(dp);
}
} catch(Exception e){
throw new RuntimeException("發送失敗");
}
}
}