深入淺出PingUDP

一、PingUDP端口探究

UDP(User Datagram Protocol 用戶數據報協議)是不可靠的傳輸層協議,它不保證數據傳輸的可靠性和有序性,但具有較小的數據包頭開銷、高效率、快速傳輸等特點。而PingUDP利用UDP傳輸ICMP報文實現了類似Ping的功能,但是在使用中也會出現交互性問題,其中一個常見問題就是端口不正確。

在PingUDP發送ICMP報文時,需要指定目的端口,否則將無法接收到響應,因此我們需要明確PingUDP所使用的默認端口號,或者自行指定端口號來保證正確的通信。

using System.Net.Sockets;
public class PingUDPClient
{
    private readonly UdpClient _udpClient;

    public PingUDPClient(int port = 0)
    {
        _udpClient = new UdpClient(port);
    }

    // ...
}

二、PingUDP端口號的選擇

在實際使用PingUDP時,我們可能需要根據具體的場景自行選擇合適的端口號,以避免端口衝突或其他問題。但並不是所有的端口號都適用於PingUDP。

首先,需要考慮到端口號的非系統預留性,例如1024以下的端口號通常都被系統佔用,而且應用程序必須擁有管理員權限才能夠使用。其次,還應該注意到安全性問題,使用常見的端口號(如80, 443, 21等)可能會被惡意軟件攻擊,因此需要使用不易被掃描的、較為隨機的端口號。

using System.Net.Sockets;
public class PingUDPClient
{
    private readonly UdpClient _udpClient;

    public PingUDPClient(int port = 0)
    {
        // 可以使用一個隨機的端口號
        if (port == 0) 
        {
            var random = new Random();
            byte[] buffer = new byte[2];
            random.NextBytes(buffer);
            port = (buffer[0] << 8) + buffer[1];
        }

        _udpClient = new UdpClient(port);
    }

    // ...
}

三、PingUDP的包頭和數據

UDP報文不僅僅包含了數據的內容,還包含了報文的首部。在PingUDP中,報文的首部包含了類型、代碼、校驗和等信息,且與Ping不同的是,PingUDP將這些信息放在了數據部分。

具體而言,PingUDP的報文結構如下:

 0               1               2               3         
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Type      |     Code      |          Checksum             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|             Identifier          |           Sequence Number    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                            Data (200 Bytes Max)               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

其中,Type佔一個位元組,表示消息類型。Code也佔一個位元組,表示消息的子類型。Checksum佔用兩個位元組,表示整個報文的校驗和。Identifier佔用兩個位元組,Sequence Number佔用兩個位元組,都是為了確定每個PingUDP包的唯一性。而Data最多只有200位元組,用於傳遞不同的測試數據。

using System.Net.Sockets;
public class PingUDPClient
{
    private readonly UdpClient _udpClient;

    public PingUDPClient(int port = 0)
    {
        // ...
    }

    public byte[] SendPing(string hostNameOrAddress, int timeout = 5000)
    {
        IPAddress ipAddress;

        try
        {
            ipAddress = Dns.GetHostAddresses(hostNameOrAddress)[0];
        }
        catch (Exception ex)
        {
            throw new Exception("解析主機名或IP地址失敗:", ex);
        }

        var pingData = new byte[200];

        // 填充數據部分
        new Random().NextBytes(pingData);

        // 填充頭部
        pingData[0] = 8; // Echo Request
        pingData[1] = 0; // Subcode

        var checksum = Checksum(pingData);
        pingData[2] = (byte)(checksum >> 8); // 高位位元組
        pingData[3] = (byte)checksum; // 低位位元組

        // ...

        return null;
    }

    private ushort Checksum(byte[] buffer)
    {
        // ...
    }
}

四、PingUDP的超時處理方式

PingUDP的超時處理方式與Ping類似,都需要設置一個等待時間。但是PingUDP要比Ping更為靈活,因為它可以通過網絡中的路由器設備分散流量,從而避免網絡擁塞和丟包問題。在PingUDP中,我們可以通過設置TTL(Time To Live)和Don’t Fragment(DF)來控制流量。

具體而言,TTL表示生存時間,每經過一個路由器,TTL值就會減1,當TTL值為0時,路由器會把報文丟棄。Don’t Fragment表示不要分片,如果報文長度超出了所經過的某個路由器的MTU(Maximum Transmission Unit),該路由器會將報文拆分成幾個小片進行傳輸,但是設置了該標誌後,路由器就會丟棄該報文。

using System.Net.Sockets;
public class PingUDPClient
{
    // ...

    public byte[] SendPing(string hostNameOrAddress, int timeout = 5000)
    {
        // ...

        _udpClient.Send(pingData, pingData.Length, new IPEndPoint(ipAddress, 0));

        var startTime = Environment.TickCount;

        var receivedData = _udpClient.Receive(ref ipAddress, ref port);

        var roundTripTime = Environment.TickCount - startTime;

        // ...

        return null;
    }
}

原創文章,作者:YATP,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/138381.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
YATP的頭像YATP
上一篇 2024-10-04 00:19
下一篇 2024-10-04 00:19

相關推薦

  • 深入淺出統計學

    統計學是一門關於收集、分析、解釋和呈現數據的學科。它在各行各業都有廣泛應用,包括社會科學、醫學、自然科學、商業、經濟學、政治學等等。深入淺出統計學是指想要學習統計學的人能夠理解統計…

    編程 2025-04-25
  • 深入淺出torch.autograd

    一、介紹autograd torch.autograd 模塊是 PyTorch 中的自動微分引擎。它支持任意數量的計算圖,可以自動執行前向傳遞、後向傳遞和計算梯度,同時提供很多有用…

    編程 2025-04-24
  • 深入淺出SQL佔位符

    一、什麼是SQL佔位符 SQL佔位符是一種佔用SQL語句中某些值的標記或佔位符。當執行SQL時,將使用該標記替換為實際的值,並將這些值傳遞給查詢。SQL佔位符使查詢更加安全,防止S…

    編程 2025-04-24
  • 深入淺出:理解nginx unknown directive

    一、概述 nginx是目前使用非常廣泛的Web服務器之一,它可以運行在Linux、Windows等不同的操作系統平台上,支持高並發、高擴展性等特性。然而,在使用nginx時,有時候…

    編程 2025-04-24
  • 深入淺出ThinkPHP框架

    一、簡介 ThinkPHP是一款開源的PHP框架,它遵循Apache2開源協議發佈。ThinkPHP具有快速的開發速度、簡便的使用方式、良好的擴展性和豐富的功能特性。它的核心思想是…

    編程 2025-04-24
  • 深入淺出arthas火焰圖

    arthas是一個非常方便的Java診斷工具,包括很多功能,例如JVM診斷、應用診斷、Spring應用診斷等。arthas使診斷問題變得更加容易和準確,因此被廣泛地使用。artha…

    編程 2025-04-24
  • 深入淺出AWK -v參數

    一、功能介紹 AWK是一種強大的文本處理工具,它可以用於數據分析、報告生成、日誌分析等多個領域。其中,-v參數是AWK中一個非常有用的參數,它用於定義一個變量並賦值。下面讓我們詳細…

    編程 2025-04-24
  • 深入淺出Markdown文字顏色

    一、Markdown文字顏色的背景 Markdown是一種輕量級標記語言,由於其簡單易學、易讀易寫,被廣泛應用於博客、文檔、代碼注釋等場景。Markdown支持使用HTML標籤,因…

    編程 2025-04-23
  • 深入淺出runafter——異步任務調度器的實現

    一、runafter是什麼? runafter是一個基於JavaScript實現的異步任務調度器,可以幫助開發人員高效地管理異步任務。利用runafter,開發人員可以輕鬆地定義和…

    編程 2025-04-23
  • 深入淺出TermQuery

    一、TermQuery概述 TermQuery是Lucene中最基本、最簡單、最常見的查詢方法之一。它完全符合其名字,意味着只能對一個單詞進行查詢。 TermQuery可以用於搜索…

    編程 2025-04-23

發表回復

登錄後才能評論