宅男在线永久免费观看网直播,亚洲欧洲日产国码无码久久99,野花社区在线观看视频,亚洲人交乣女bbw,一本一本久久a久久精品综合不卡

全部
常見(jiàn)問(wèn)題
產(chǎn)品動(dòng)態(tài)
精選推薦

用Go實(shí)現(xiàn)Ping操作

管理 管理 編輯 刪除


Ping 是什么?

? ping 是一個(gè)計(jì)算機(jī)網(wǎng)絡(luò)工具,通常用于測(cè)試網(wǎng)絡(luò)連接的可達(dá)性和測(cè)量往返時(shí)間。在大多數(shù)操作系統(tǒng)中,ping 命令是一個(gè)內(nèi)置的命令行工具,可以通過(guò)命令行終端使用。例如,在 Windows 操作系統(tǒng)中,你可以在命令提示符中運(yùn)行 ping 命令,而在類 Unix 操作系統(tǒng)(如 Linux 和 macOS)中,你可以在終端中使用 ping 命令。通常,命令的語(yǔ)法是 ping 目標(biāo)主機(jī)或 IP,然后命令將輸出與目標(biāo)主機(jī)的通信狀態(tài)和 RTT 相關(guān)的信息。

Ping 有什么用處?

? Ping 工具主要有以下幾個(gè)主要用途:

  1. 測(cè)試主機(jī)的可達(dá)性ping 命令用于檢查另一個(gè)主機(jī)是否可以在網(wǎng)絡(luò)上訪問(wèn)。它向目標(biāo)主機(jī)發(fā)送一個(gè)小的數(shù)據(jù)包(通常是 ICMP Echo Request),如果目標(biāo)主機(jī)正常工作,它將響應(yīng)一個(gè)回復(fù)數(shù)據(jù)包(通常是 ICMP Echo Reply)。如果沒(méi)有響應(yīng),那么目標(biāo)主機(jī)可能無(wú)法訪問(wèn)或處于離線狀態(tài)。
  2. 測(cè)量往返時(shí)間(RTT)ping 命令通常會(huì)顯示每次請(qǐng)求和響應(yīng)之間的時(shí)間差,這被稱為往返時(shí)間(RTT)。這個(gè)值表示了數(shù)據(jù)從發(fā)送端到接收端的往返延遲,通常以毫秒為單位。測(cè)量 RTT 對(duì)于評(píng)估網(wǎng)絡(luò)性能和延遲非常有用。
  3. 網(wǎng)絡(luò)故障排除ping 是網(wǎng)絡(luò)故障排除的有用工具之一。通過(guò)檢查 ping 的輸出,網(wǎng)絡(luò)管理員可以確定網(wǎng)絡(luò)連接是否正常,以及延遲是否在可接受范圍內(nèi)。如果 ping 失敗,管理員可以進(jìn)一步調(diào)查網(wǎng)絡(luò)故障的原因。
  4. 監(jiān)測(cè)網(wǎng)絡(luò)穩(wěn)定性ping 命令還可以用于監(jiān)測(cè)網(wǎng)絡(luò)的穩(wěn)定性。通過(guò)連續(xù)地向目標(biāo)主機(jī)發(fā)送 ping 請(qǐng)求,可以了解網(wǎng)絡(luò)連接的質(zhì)量和穩(wěn)定性。如果出現(xiàn)不穩(wěn)定性,管理員可以及時(shí)采取措施。

動(dòng)手實(shí)現(xiàn)一個(gè) Ping 工具

? 首先,我們要了解一下 Ping 操作的工作原理:向網(wǎng)絡(luò)上的另一個(gè)主機(jī)系統(tǒng)發(fā)送 ICMP 報(bào)文,如果指定系統(tǒng)得到了報(bào)文,它將把回復(fù)報(bào)文傳回給發(fā)送者。

? ICMP 報(bào)文由 ICMP 報(bào)文頭 和 數(shù)據(jù)包組成,其報(bào)文頭包含 Type、Code、Checksum、ID、SequenceNum 字段。因此,我們需要先在本地主機(jī)上定義 ICMP 請(qǐng)求報(bào)文結(jié)構(gòu)體:

type ICMP struct {
    Type        uint8  // 類型
    Code        uint8  // 代碼
    CheckSum    uint16 // 校驗(yàn)和
    ID          uint16 // ID
    SequenceNum uint16 // 序號(hào)
}

? 上面只是 ICMP 的報(bào)文頭,我們?cè)诤竺孢€需要為這個(gè)報(bào)文構(gòu)建請(qǐng)求數(shù)據(jù)。需要注意的是,定義的順序不能亂,因?yàn)槲覀儼l(fā)送數(shù)據(jù)包是按字節(jié)發(fā)送的,所以獲取對(duì)應(yīng)的字段的時(shí)候,也是按照對(duì)應(yīng)字段的位置去獲取的,如果順序亂了,獲取到的數(shù)據(jù)就會(huì)出錯(cuò)。

? 在構(gòu)建數(shù)據(jù)之前,我們先設(shè)置好命令行參數(shù),以獲取對(duì)應(yīng)參數(shù)和目標(biāo) IP,同時(shí)需要定義全局變量,將命令行參數(shù)綁定到對(duì)應(yīng)的變量中,方便使用:

var (
    helpFlag bool
    timeout  int64 // 耗時(shí)
    size     int   // 大小
    count    int   // 請(qǐng)求次數(shù)
)

func GetCommandArgs() {
    flag.Int64Var(&timeout, "w", 1000, "請(qǐng)求超時(shí)時(shí)間")
    flag.IntVar(&size, "l", 32, "發(fā)送字節(jié)數(shù)")
    flag.IntVar(&count, "n", 4, "請(qǐng)求次數(shù)")
    flag.BoolVar(&helpFlag, "h", false, "顯示幫助信息")
    flag.Parse()
}

? 在 main 函數(shù)中,啟用命令行參數(shù)設(shè)置:

func main() {
    GetCommandArgs()
}

? 在發(fā)送報(bào)文前,我們需要先建立連接,此時(shí)需要先獲取目標(biāo) IP,這個(gè)由命令行參數(shù)中獲?。?/p>

// 獲取目標(biāo) IP
desIP := os.Args[len(os.Args)-1]
// 構(gòu)建連接
conn, err := net.DialTimeout("ip:icmp", desIP, time.Duration(timeout)*time.Millisecond)
if err != nil {
    log.Println(err.Error())
    return
}
defer conn.Close()
// 遠(yuǎn)程地址
remoteaddr := conn.RemoteAddr()

? 連接建立后,我們需要根據(jù)參數(shù)中的發(fā)送次數(shù) count 去發(fā)送對(duì)應(yīng)次數(shù)的報(bào)文,因此需要用 for 去做:

for i := 0; i < count; i ++ {
    ...
}

? 同樣,我們?cè)谌肿兞恐刑砑訉?duì)應(yīng)的值:

var (
    typ      uint8 = 8
    code     uint8 = 0
)

? 做好前面的準(zhǔn)備工作,我們就可以開(kāi)始構(gòu)建我們的 ICMP 請(qǐng)求報(bào)文了。我們這里以發(fā)送的第幾次作為 ID 和序列號(hào):

icmp := &ICMP{
        Type:        typ,
        Code:        code,
        CheckSum:    uint16(0),
        ID:          uint16(i),
        SequenceNum: uint16(i),
    }

? 由于 ICMP 是使用二進(jìn)制進(jìn)行傳輸?shù)模晕覀冃枰獙⑿畔⒂枚M(jìn)制表示:

var buffer bytes.Buffer
binary.Write(&buffer, binary.BigEndian, icmp)

? 然后根據(jù)發(fā)送數(shù)據(jù)的大小 size 構(gòu)建數(shù)據(jù)并寫(xiě)在 ICMP 報(bào)文后面:

data := make([]byte, size)
buffer.Write(data)
data = buffer.Bytes()

? 現(xiàn)在,就只差一個(gè)校驗(yàn)和字段了,計(jì)算 ICMP(Internet Control Message Protocol)報(bào)文的校驗(yàn)和字段遵循以下步驟:

  1. 將報(bào)文分為 16 位的字(兩個(gè)字節(jié))。
  2. 對(duì)所有字進(jìn)行按位求和(二進(jìn)制求和),包括數(shù)據(jù)部分和報(bào)文頭。如果有剩余字節(jié)(奇數(shù)個(gè)字節(jié)),將其附加到最后一個(gè)字節(jié)。
  3. 將溢出的進(jìn)位位(如果有)加回到結(jié)果中。
  4. 取結(jié)果的二進(jìn)制反碼(按位取反)

? 代碼實(shí)現(xiàn)如下:

func checkSum(data []byte) uint16 {
    // 第一步:兩兩拼接并求和
    length := len(data)
    index := 0
    var sum uint32
    for length > 1 {
        // 拼接且求和
        sum += uint32(data[index])<<8 + uint32(data[index+1])
        length -= 2
        index += 2
    }
    // 奇數(shù)情況,還剩下一個(gè),直接求和過(guò)去
    if length == 1 {
        sum += uint32(data[index])
    }

    // 第二部:高 16 位,低 16 位 相加,直至高 16 位為 0
    hi := sum >> 16
    for hi != 0 {
        sum = hi + uint32(uint16(sum))
        hi = sum >> 16
    }
    // 返回 sum 值 取反
    return uint16(^sum)
}

? 接著再將算出來(lái)的校驗(yàn)和放到報(bào)文頭對(duì)應(yīng)的位置中去,這里需要計(jì)算一下位置。假設(shè)我們有以下 ICMP 報(bào)文:

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      Type       |      Code       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Checksum (2 bytes)       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Identifier (2 bytes)   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|        Sequence Number (2 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Data (variable length) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

? 校驗(yàn)和屬于報(bào)文的第3、4個(gè)字節(jié),即 data[2] 和 data[3]。

data[2] = byte(checkSum >> 8)
data[3] = byte(checkSum)

? 最后再設(shè)置一下超時(shí)時(shí)間,就可以將數(shù)據(jù) data 寫(xiě)入連接中了:

// 設(shè)置超時(shí)時(shí)間
conn.SetDeadline(time.Now().Add(time.Duration(timeout) * time.Millisecond))

// 將 data 寫(xiě)入連接中,
n, err := conn.Write(data)
if err != nil {
    log.Println(err)
    continue
}

? 發(fā)送完成后,再構(gòu)建緩沖接收響應(yīng)包,

buf := make([]byte, 1024)
n, err = conn.Read(buf)
//fmt.Println(data)
if err != nil {
    log.Println(err)
    continue
}

? 然后我們就可以從響應(yīng)包中獲取我們需要的數(shù)據(jù),比如 IP 地址、TTL等:

? 根據(jù)抓到的 ICMP 響應(yīng)包,可以知道 IP 頭共 20 個(gè)字節(jié),源 IP 和 目標(biāo) IP 在我們接收的數(shù)據(jù)包的倒數(shù) 8 個(gè)字節(jié)里,所以我們可以推算出我們?cè)L問(wèn)的 IP 地址,就可以構(gòu)建我們的打印信息了:

fmt.Printf("來(lái)自 %d.%d.%d.%d 的回復(fù):字節(jié)=%d 時(shí)間=%d TTL=%d\n", buf[12], buf[13], buf[14], buf[15], n-28, t, buf[8])

? 至此,我們 Ping 工具的核心功能就實(shí)現(xiàn)了,還有一些統(tǒng)計(jì)信息,就不做具體的講解了,感興趣的可以從代碼中看具體的實(shí)現(xiàn)。

完整代碼如下:

package main

import (
    "bytes"
    "encoding/binary"
    "flag"
    "fmt"
    "log"
    "math"
    "net"
    "os"
    "time"
)

// tcp 報(bào)文前20個(gè)是報(bào)文頭,后面的才是 ICMP 的內(nèi)容。
// ICMP:組建 ICMP 首部(8 字節(jié)) + 我們要傳輸?shù)膬?nèi)容
// ICMP 首部:type、code、校驗(yàn)和、ID、序號(hào),1 1 2 2 2
// 回顯應(yīng)答:type = 0,code = 0
// 回顯請(qǐng)求:type = 8, code = 0

var (
    helpFlag bool
    timeout  int64 // 耗時(shí)
    size     int   // 大小
    count    int   // 請(qǐng)求次數(shù)
    typ      uint8 = 8
    code     uint8 = 0
    SendCnt  int                   // 發(fā)送次數(shù)
    RecCnt   int                   // 接收次數(shù)
    MaxTime  int64 = math.MinInt64 // 最大耗時(shí)
    MinTime  int64 = math.MaxInt64 // 最短耗時(shí)
    SumTime  int64                 // 總計(jì)耗時(shí)
)

// ICMP 序號(hào)不能亂
type ICMP struct {
    Type        uint8  // 類型
    Code        uint8  // 代碼
    CheckSum    uint16 // 校驗(yàn)和
    ID          uint16 // ID
    SequenceNum uint16 // 序號(hào)
}

func main() {
    fmt.Println()
    log.SetFlags(log.Llongfile)
    GetCommandArgs()

    // 打印幫助信息
    if helpFlag {
        displayHelp()
        os.Exit(0)
    }

    // 獲取目標(biāo) IP
    desIP := os.Args[len(os.Args)-1]
    //fmt.Println(desIP)
    // 構(gòu)建連接
    conn, err := net.DialTimeout("ip:icmp", desIP, time.Duration(timeout)*time.Millisecond)
    if err != nil {
        log.Println(err.Error())
        return
    }
    defer conn.Close()
    // 遠(yuǎn)程地址
    remoteaddr := conn.RemoteAddr()
    fmt.Printf("正在 Ping %s [%s] 具有 %d 字節(jié)的數(shù)據(jù):\n", desIP, remoteaddr, size)
    for i := 0; i < count; i++ {
        // 構(gòu)建請(qǐng)求
        icmp := &ICMP{
            Type:        typ,
            Code:        code,
            CheckSum:    uint16(0),
            ID:          uint16(i),
            SequenceNum: uint16(i),
        }

        // 將請(qǐng)求轉(zhuǎn)為二進(jìn)制流
        var buffer bytes.Buffer
        binary.Write(&buffer, binary.BigEndian, icmp)
        // 請(qǐng)求的數(shù)據(jù)
        data := make([]byte, size)
        // 將請(qǐng)求數(shù)據(jù)寫(xiě)到 icmp 報(bào)文頭后
        buffer.Write(data)
        data = buffer.Bytes()
        // ICMP 請(qǐng)求簽名(校驗(yàn)和):相鄰兩位拼接到一起,拼接成兩個(gè)字節(jié)的數(shù)
        checkSum := checkSum(data)
        // 簽名賦值到 data 里
        data[2] = byte(checkSum >> 8)
        data[3] = byte(checkSum)
        startTime := time.Now()

        // 設(shè)置超時(shí)時(shí)間
        conn.SetDeadline(time.Now().Add(time.Duration(timeout) * time.Millisecond))

        // 將 data 寫(xiě)入連接中,
        n, err := conn.Write(data)
        if err != nil {
            log.Println(err)
            continue
        }
        // 發(fā)送數(shù) ++
        SendCnt++
        // 接收響應(yīng)
        buf := make([]byte, 1024)
        n, err = conn.Read(buf)
        //fmt.Println(data)
        if err != nil {
            log.Println(err)
            continue
        }
        // 接受數(shù) ++
        RecCnt++
        //fmt.Println(n, err) // data:64,ip首部:20,icmp:8個(gè) = 92 個(gè)
        // 打印信息
        t := time.Since(startTime).Milliseconds()
        fmt.Printf("來(lái)自 %d.%d.%d.%d 的回復(fù):字節(jié)=%d 時(shí)間=%d TTL=%d\n", buf[12], buf[13], buf[14], buf[15], n-28, t, buf[8])
        MaxTime = Max(MaxTime, t)
        MinTime = Min(MinTime, t)
        SumTime += t
        time.Sleep(time.Second)
    }

    fmt.Printf("\n%s 的 Ping 統(tǒng)計(jì)信息:\n", remoteaddr)
    fmt.Printf("    數(shù)據(jù)包: 已發(fā)送 = %d,已接收 = %d,丟失 = %d (%.f%% 丟失),\n", SendCnt, RecCnt, count*2-SendCnt-RecCnt, float64(count*2-SendCnt-RecCnt)/float64(count*2)*100)
    fmt.Println("往返行程的估計(jì)時(shí)間(以毫秒為單位):")
    fmt.Printf("    最短 = %d,最長(zhǎng) = %d,平均 = %d\n", MinTime, MaxTime, SumTime/int64(count))
}

// 求校驗(yàn)和
func checkSum(data []byte) uint16 {
    // 第一步:兩兩拼接并求和
    length := len(data)
    index := 0
    var sum uint32
    for length > 1 {
        // 拼接且求和
        sum += uint32(data[index])<<8 + uint32(data[index+1])
        length -= 2
        index += 2
    }
    // 奇數(shù)情況,還剩下一個(gè),直接求和過(guò)去
    if length == 1 {
        sum += uint32(data[index])
    }

    // 第二部:高 16 位,低 16 位 相加,直至高 16 位為 0
    hi := sum >> 16
    for hi != 0 {
        sum = hi + uint32(uint16(sum))
        hi = sum >> 16
    }
    // 返回 sum 值 取反
    return uint16(^sum)
}

// GetCommandArgs 命令行參數(shù)
func GetCommandArgs() {
    flag.Int64Var(&timeout, "w", 1000, "請(qǐng)求超時(shí)時(shí)間")
    flag.IntVar(&size, "l", 32, "發(fā)送字節(jié)數(shù)")
    flag.IntVar(&count, "n", 4, "請(qǐng)求次數(shù)")
    flag.BoolVar(&helpFlag, "h", false, "顯示幫助信息")
    flag.Parse()
}

func Max(a, b int64) int64 {
    if a > b {
        return a
    }
    return b
}

func Min(a, b int64) int64 {
    if a < b {
        return a
    }
    return b
}

func displayHelp() {
    fmt.Println(`選項(xiàng):
    -n count       要發(fā)送的回顯請(qǐng)求數(shù)。
    -l size        發(fā)送緩沖區(qū)大小。
    -w timeout     等待每次回復(fù)的超時(shí)時(shí)間(毫秒)。
    -h            幫助選項(xiàng)`)
}

作者:panco68120
鏈接:https://juejin.cn/post/7357142305423933494
來(lái)源:稀土掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。


請(qǐng)登錄后查看

小碼二開(kāi) 最后編輯于2024-05-16 15:53:49

快捷回復(fù)
回復(fù)
回復(fù)
回復(fù)({{post_count}}) {{!is_user ? '我的回復(fù)' :'全部回復(fù)'}}
排序 默認(rèn)正序 回復(fù)倒序 點(diǎn)贊倒序

{{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level || item.bbs_level }}

作者 管理員 企業(yè)

{{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推薦': '推薦'}}
{{item.is_suggest == 1? '取消推薦': '推薦'}}
沙發(fā) 板凳 地板 {{item.floor}}#
{{item.user_info.title || '暫無(wú)簡(jiǎn)介'}}
附件

{{itemf.name}}

{{item.created_at}}  {{item.ip_address}}
打賞
已打賞¥{{item.reward_price}}
{{item.like_count}}
{{item.showReply ? '取消回復(fù)' : '回復(fù)'}}
刪除
回復(fù)
回復(fù)

{{itemc.user_info.nickname}}

{{itemc.user_name}}

回復(fù) {{itemc.comment_user_info.nickname}}

附件

{{itemf.name}}

{{itemc.created_at}}
打賞
已打賞¥{{itemc.reward_price}}
{{itemc.like_count}}
{{itemc.showReply ? '取消回復(fù)' : '回復(fù)'}}
刪除
回復(fù)
回復(fù)
查看更多
打賞
已打賞¥{{reward_price}}
874
{{like_count}}
{{collect_count}}
添加回復(fù) ({{post_count}})

相關(guān)推薦

快速安全登錄

使用微信掃碼登錄
{{item.label}} 加精
{{item.label}} {{item.label}} 板塊推薦 常見(jiàn)問(wèn)題 產(chǎn)品動(dòng)態(tài) 精選推薦 首頁(yè)頭條 首頁(yè)動(dòng)態(tài) 首頁(yè)推薦
取 消 確 定
回復(fù)
回復(fù)
問(wèn)題:
問(wèn)題自動(dòng)獲取的帖子內(nèi)容,不準(zhǔn)確時(shí)需要手動(dòng)修改. [獲取答案]
答案:
提交
bug 需求 取 消 確 定
打賞金額
當(dāng)前余額:¥{{rewardUserInfo.reward_price}}
{{item.price}}元
請(qǐng)輸入 0.1-{{reward_max_price}} 范圍內(nèi)的數(shù)值
打賞成功
¥{{price}}
完成 確認(rèn)打賞

微信登錄/注冊(cè)

切換手機(jī)號(hào)登錄

{{ bind_phone ? '綁定手機(jī)' : '手機(jī)登錄'}}

{{codeText}}
切換微信登錄/注冊(cè)
暫不綁定
CRMEB客服

CRMEB咨詢熱線 咨詢熱線

400-8888-794

微信掃碼咨詢

CRMEB開(kāi)源商城下載 源碼下載 CRMEB幫助文檔 幫助文檔
返回頂部 返回頂部
CRMEB客服