聊聊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), 此時連接就關閉了。

 

好了,關於這篇就整理到這里,如果有不對的地方歡迎批評指正。

  

  

  

 

 

   

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM