一、UDP 無連接的 高效的 基於數據報的 不可靠 的連接
主要的應用場景:
需要資源少,網絡情況穩定的內網,或者對於丟包不敏感的應用,比如 DHCP 就是基於 UDP 協議的。
不需要一對一溝通,建立連接,而是可以廣播的應用。因為它不面向連接,所以可以做到一對多,承擔廣播或者多播的協議。
需要處理速度快,可以容忍丟包,但是即使網絡擁塞,也毫不退縮,一往無前的時候
基於 UDP 的幾個例子
直播。直播對實時性的要求比較高,寧可丟包,也不要卡頓的,所以很多直播應用都基於 UDP 實現了自己的視頻傳輸協議
實時游戲。游戲的特點也是實時性比較高,在這種情況下,采用自定義的可靠的 UDP 協議,自定義重傳策略,能夠把產生的延遲降到最低,減少網絡問題對游戲造成的影響
物聯網。一方面,物聯網領域中斷資源少,很可能知識個很小的嵌入式系統,而維護 TCP 協議的代價太大了;另一方面,物聯網對實時性的要求也特別高。比如 Google 旗下的 Nest 簡歷 Thread Group,推出了物聯網通信協議 Thread,就是基於 UDP 協議的
服務器端:
//服務器端 try { DatagramSocket ds= new DatagramSocket(8887); // byte [] b= new byte[1024]; DatagramPacket dp= new DatagramPacket(b, b.length); ds.receive(dp); System.out.println("客戶端說:"+new String(dp.getData(),0,dp.getData().length)); //回復客戶端消息 要回復的地址 原來的包裹上都有 //要定義 包裹的大小 和郵寄的地址 String str= "我去洗澡了"; SocketAddress address = dp.getSocketAddress(); DatagramPacket dp1= new DatagramPacket(str.getBytes(), str.getBytes().length, address); ds.send(dp1); //關閉資源。。。。。 ds.close(); } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
客戶端:
//udp 就很類似於我們生活中的發快遞 try { // DatagramSocket ds= new DatagramSocket(); // 要發的包裹 str String str="在嗎?"; //選擇快遞地址 InetAddress address = InetAddress.getByName("localhost"); //填寫快遞單 (要傳輸的報文的byte 數組 以及起始的位置 結束的位置 地址) DatagramPacket dp= new DatagramPacket(str.getBytes(), 0, str.getBytes().length, address, 8887); //發送包裹 ds.send(dp); //接受服務器返回的 報文數據 byte [] b= new byte[1024]; DatagramPacket dp1= new DatagramPacket(b, b.length); ds.receive(dp1); System.out.println("服務器說:"+new String(dp1.getData(),0,dp1.getData().length)); ds.close(); } catch (SocketException e) { e.printStackTrace(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
TCP:可靠的連接 面向連接 基於流 效率相對較低 安全
// 服務器端要先向設備申請端口號 以便接受客戶端的數據流 ServerSocket ss = null; Socket s = null; InputStream inputStream = null; OutputStream outputStream = null; try { ss = new ServerSocket(9999); s = ss.accept(); inputStream = s.getInputStream(); byte[] b = new byte[inputStream.available()]; int len = 0; while ((len = inputStream.read(b)) != -1) { System.out.println(new String(b, 0, len)); } // 向客戶端回應下 outputStream = s.getOutputStream(); outputStream.write("我要去洗澡了".getBytes()); outputStream.flush(); } catch (IOException e) { e.printStackTrace(); } finally { // 關閉資源 try { if (outputStream != null) { outputStream.close(); } if (inputStream != null) { inputStream.close(); } if (s != null) { s.close(); } } catch (IOException e) { e.printStackTrace(); } }
//客戶端 Socket s = null; OutputStream outputStream = null; InputStream inputStream =null; try { s = new Socket("localhost", 9999); outputStream = s.getOutputStream(); outputStream.write("在?".getBytes()); // outputStream.flush(); //關閉套接字 s.shutdownOutput(); //接受服務端的回應 inputStream = s.getInputStream(); BufferedReader bb= new BufferedReader(new InputStreamReader(inputStream)); String readLine = bb.readLine(); System.out.println(readLine); //下邊的代碼有問題 死循環 // byte [] b= new byte[1024]; // int len =0; // while ((len= inputStream.read(b))!=-1) { // System.out.println(new String(b, 0, len)); // } inputStream.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (outputStream != null) { outputStream.close(); } if (s != null) { s.close(); } } catch (IOException e) { e.printStackTrace(); } }
面試:
兩者的區別
- TCP 是面向連接的,UDP 是面向無連接的
- UDP程序結構較簡單
- TCP 是面向字節流的,UDP 是基於數據報的
- TCP 保證數據正確性,UDP 可能丟包
- TCP 保證數據順序,UDP 不保證
TCP 為什么是可靠連接
- 通過 TCP 連接傳輸的數據無差錯,不丟失,不重復,且按順序到達。
- TCP 報文頭里面的序號能使 TCP 的數據按序到達
- 報文頭里面的確認序號能保證不丟包,累計確認及超時重傳機制
- TCP 擁有流量控制及擁塞控制的機制