首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

用 Visual C# 實作 ICMP 協議與 Ping 功能(四):ICMP 封包結構與 IcmpPacket 類別設計

     編輯:關於C語言

Ping 執行的三大關鍵步驟

  1. 定義 ICMP 封包結構 (對應 RFC 792)
  2. 客戶端發送 封裝 ICMP Echo Request 的 IP 封包
  3. 客戶端接收 封裝 ICMP Echo Reply 的 IP 封包

IP 封包與 ICMP 封包關係圖解

IP 封包結構

圖 03:IP 封包組成結構 — 前 20 bytes 為 IP 標頭,其後為選項與資料 (即 ICMP 封包)

ICMP 封包結構

圖 04:ICMP 封包組成結構 — Type(1B) Code(1B) Checksum(2B) Identifier(2B) Sequence(2B) Data

IcmpPacket 類別完整實作

public class IcmpPacket
{
    private byte _type;          // 類型
    private byte _subCode;       // 代碼
    private ushort _checkSum;    // 檢驗和
    private ushort _identifier;  // 識別符
    private ushort _sequenceNumber; // 序列號
    private byte[] _data;        // 選項資料

    public IcmpPacket(byte type, byte subCode, ushort checkSum,
                      ushort identifier, ushort sequenceNumber, int dataSize)
    {
        _type = type;
        _subCode = subCode;
        _checkSum = checkSum;
        _identifier = identifier;
        _sequenceNumber = sequenceNumber;
        _data = new byte[dataSize];
        for (int i = 0; i < dataSize; i++)
            _data[i] = (byte)'#'; // 填充任意資料
    }

    public ushort CheckSum
    {
        get { return _checkSum; }
        set { _checkSum = value; }
    }

    // 序列化為位元組陣列
    public int CountByte(byte[] buffer)
    {
        int i = 0;
        byte[] b_type = new byte[1] { _type };
        byte[] b_code = new byte[1] { _subCode };
        byte[] b_cksum = BitConverter.GetBytes(_checkSum);
        byte[] b_id = BitConverter.GetBytes(_identifier);
        byte[] b_seq = BitConverter.GetBytes(_sequenceNumber);

        Array.Copy(b_type, 0, buffer, i, b_type.Length); i += b_type.Length;
        Array.Copy(b_code, 0, buffer, i, b_code.Length); i += b_code.Length;
        Array.Copy(b_cksum, 0, buffer, i, b_cksum.Length); i += b_cksum.Length;
        Array.Copy(b_id, 0, buffer, i, b_id.Length); i += b_id.Length;
        Array.Copy(b_seq, 0, buffer, i, b_seq.Length); i += b_seq.Length;
        Array.Copy(_data, 0, buffer, i, _data.Length); i += _data.Length;
        return i;
    }

    // Internet 檢驗和演算法 (RFC 1071)
    public static ushort SumOfCheck(ushort[] buffer)
    {
        int cksum = 0;
        for (int i = 0; i < buffer.Length; i++)
            cksum += buffer[i];
        cksum = (cksum >> 16) + (cksum & 0xffff);
        cksum += (cksum >> 16);
        return (ushort)(~cksum);
    }
}

設計重點說明

  • 雙次序列化:第一次序列化得位元組陣列 → 計算檢驗和 → 更新 _checkSum → 第二次序列化產生最終送出資料。
  • Big-Endian 網路序:BitConverter.GetBytes 產生 Little-Endian,但在 x86 平台上 Raw Socket 直接發送位元組陣列即可,網路層會處理位序轉換。
  • Identifier 與 SequenceNumber:用於多執行緒或多進程環境下配對請求/回應,本範例固定值簡化示範。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved