聊聊UDP、TCP和實現一個簡單的JAVA UDP小Demo
最近真的比較忙,很久就想寫了,可是一直苦於寫點什麼,今天腦袋靈光一閃,覺得自己再UDP方面還有些不瞭解的地方,所以要給自己掃盲。
好了,咱們進入今天的主題,先列一下提綱:
1. UDP是什麼,UDP適用於什麼場景?
2. 寫一個小Demo來加深一下UDP的理解。
3. UDP和TCP的區別有哪些?
4. TCP建連和關閉的過程,為什麼建立連線的時候是三次握手,斷開連線的時候需要四次?
1. UDP是什麼,UDP適用於什麼場景?
相信很多同學都聽過UDP,UDP的全稱:User Datagrame Protocol, 使用者報文協議,是一個傳輸層協議。UDP最大的特點是:不可靠網路傳輸,無連線資料協議,即傳送前不要連線,直接向目標地址傳送。而TCP和UDP基本上是相互補充的,TCP是可靠的資料資料傳輸,基於連線後的資料傳送。
TCP是Transmission Control Protocol,傳輸控制協議,TCP是基於可靠的資料傳輸,那麼就需要犧牲更多的延遲和網路頻寬。而UDP則不需要可靠的資料傳輸,那麼將會需要更小的網路延遲和網路開銷。UDP可以允許丟棄延遲的資料包。由於低延遲低頻寬,所以UDP非常適合電腦遊戲,語音電話,視訊電話,網路直播。
我們接下來看一下UDP的Packet的組成(圖片來源網路),8位元組的Header,然後就是UDP的資料。本機如果作為客戶端的話,本機的埠號為0-65535,也就是本機連線外部機器的話最多可以連線65536,0是保留埠號。如果作為服務端的話,可以使用的埠為2的32次方個埠。也就是可以接收的資料可以有這麼多。當然,目前一臺機器能處理的資料沒有這麼多。
8位元組的Header,很簡單也比較少,不像TCP需要20-60位元組的資料。
Source port,源埠號,16位2個位元組。
Length, 資料的長度2個位元組。
Distination port, 目標埠,用於識別到目標機器的埠號。2個位元組。
Checksum, 用於計算Header的Checksum(校驗值)。
2. 寫一個小Demo來加深一下UDP的理解。
1) UDP的服務端程式碼,因為UDP的程式碼都是JDK自帶的,所以也不需要引入其他jar包就可以。
2)Server端主要建立步驟:
a) 建立一個監聽udp的埠號 8888.
b) 建立一個用於接收資料的DatagramPacket,引數有兩個,一個是資料,一個是資料的長度。
c) 採用迴圈進行receive資料,直到收到的bye字串。
package myflink.udp; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; /** * @author huangqingshi * @Date 2020-05-24 */ public class UDPServer { public static void main(String[] args) throws IOException { //1. 建立一個監聽8888埠的udp socket DatagramSocket ds = new DatagramSocket(8888); //設定接收資料的最大值 byte[] receive = new byte[65535]; //用於接收的資料 DatagramPacket datagramPacket = null; while(true) { //2. 建立一個用於接收資料。buf即資料和其長度 datagramPacket = new DatagramPacket(receive,receive.length ); //3. 接收byteBuff的資料 ds.receive(datagramPacket); System.out.println("Client:-" + data(receive)); //4. 如果接收到了bye,程式結束 if("bye".equals(data(receive))) { break; } //5.清理receive中的資料 receive = new byte[65535]; } } public static StringBuilder data(byte[] bytes) { if(bytes == null) { return null; } StringBuilder ret = new StringBuilder(); int i = 0; while (bytes[i] != 0) { ret.append((char) bytes[i]); i++; } return ret; } }
3)接下來是客戶端的程式碼,步驟如下:
a) 建立scanner用於在控制檯進行資料輸入,然後建立一個DatagramSocket用於處理資料。
b) 建立一個DatagramPacket用於資料的傳送。
c) 進行資料傳送。
d) 持續傳送資料,當收到bye字串的話就會結束。
package myflink.udp; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.util.Scanner; /** * @author huangqingshi * @Date 2020-05-24 */ public class UDPClient { public static void main(String[] args) throws IOException { Scanner scanner = new Scanner(System.in); InetAddress ip = InetAddress.getLocalHost(); //1. 建立一個socket物件用於處理資料 DatagramSocket socket = new DatagramSocket(); //用於存放資料 byte[] buf = null; //一個死迴圈,用於接收資料後處理,收到bye後結束處理 while(true) { String input = scanner.nextLine(); //將接收到的資訊轉換為byte陣列 buf = input.getBytes(); //2. 建立一個DatagramPack包用於建立傳送的資料 DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length, ip, 8888); //3. 傳送資料 socket.send(datagramPacket); //4. 如果收到了byte直接結束迴圈 if("bye".equals(input)) { break; } } } }
啟動服務端和客戶端,然後再控制檯輸入一些測試資料,看一下服務端的控制檯輸出:
客戶端輸入資料 Hello UDP 服務端的輸出資料 Client:-Hello UDP
好了Demo已經執行完了,非常簡單。
3. UDP和TCP的區別有哪些?
1. TCP是可靠的傳輸,而UDP是非可靠資料傳輸。因為可靠,所以需要更高的延遲和網路頻寬。而UDP則不需要,所以比較適合語音、視訊電話等。
2. UDP的Header位元組為8個位元組,非常少,而TCP需要至少20個位元組。
3. TCP是全雙工的,即可以傳送接收資料,可以想象兩個人打電話,即可以聽到聲音又可以傳送聲音。而UDP傳送資料的時候才連線,傳送完資料之後不會保留連線。
4. TCP是點對點連線的,而UDP是多對多進行資料傳輸。TCP以位元組流形式傳送,有擁塞控制,方式傳送資料量太大擁塞。而UDP是以報文形式傳送給目標機器,沒有擁塞控制。
4. TCP建連和關閉的過程,為什麼建立連線的時候是三次握手,斷開連線的時候需要四次?
1)三次握手建立連線處理:
1. 首先建立連線時client需要傳送一個SYN+隨機sequence給 server 端,這是客戶端的狀態是SYN_SENT狀態。
2. server收到資料後會回覆一個SYN+ACK,ACK為接收到的sequence+1,同時再發送一個sequence。server的狀態為ACK_REVD。
3. client再把收到的sequnce+1作為ACK再給到服務端,然後服務端和客戶端的狀態都是ESTABLISHED。說明連線建立了。
第二步中的SYN和ACK可以同時傳送,這兩個值同時傳送不受影響,都可以建立連線。當然如果兩步分開發送也是可以的,但是由於可以節省一步傳送,所以不用多費事。
2)四次握手關閉連線處理:
1. client發一個FIN和一個隨機的sequence給server,然後客戶端的狀態變為FIN_WAIT_1狀態。
2. server收到了FIN後,狀態變為CLOSE_WAIT,然後再把接收到的sequence+1和ACK標誌返回給client。client收到ACK後變為FIN_WAIT2狀態。
3. 然後server再次給client傳送一個FIN+sequence給client,此時客戶端的狀態變為TIME_WAIT狀態。
4. client再把收到的sequence + 1傳送給server, 此時server的狀態變為CLOSED。此時連線正式斷開。
這是客戶端主動發起關閉連線的過程,還有同時傳送FIN標誌的情況。
1. client傳送FIN+sequence給server端,狀態變為FIN_WAIT_1。
2. server也傳送FIN+sequence給client端,此時server的狀態變為FIN_WAIT_1。client的接收FIN後變為CLOSING,同時server也變為CLOSING。
3. client傳送ACK+接收到的sequence+1給server。client的狀態變為TIME_WAIT。
4. server同時也傳送ACK+接收到的seqnce+1給client。此時client和server都變為CLOSED。
整個過程是這麼一個過程,那麼為什麼TCP連線的時候需要三次,而關閉的時候需要四次?
因為建立連線的時候SYN+ACK可以同時傳送,不影響連線建立。而關閉的時候FIN+ACK不能合起來,因為TCP是雙向且全雙工連線。也就是client和server建立好連線後,client和server即能傳送資訊同時也能接收資訊。當client傳送FIN給server的時候,只能說明客戶端不給server傳送資料了,但是不證明client不接收資料,所以給到server後,server處理好之後說我也不給你發資料了(FIN)。然後我已經你不給我發資料了(ACK),這個時候client收到後說知道了(ACK), 此時連線就關閉了。
好了,關於這篇就整理到這裡,如果有不對的地方歡迎批評指正。