ping是使用icmp協議
icmp協議的組成:type(8bits) + code(8bits) + 校驗碼(checksum,8bits) + id(16bits) + 序號(sequence,16bits) + 資料
這些組成部分的含義:
1)type icmp的型別,標識生成的錯誤報文
2)code 進一步劃分icmp的型別,該欄位用來查詢產生的原因;例如,icmp的目標不可達型別可以把這個位設為1至15等來表示不同的意思。
3)checksum 校驗碼部分,這個字段包含從icmp報頭和資料部分計算得來的,用於檢查錯誤的,其中此校驗碼欄位的值視為0.
4)id 這個字段包含了id值,在echo reply型別的訊息中要返回這個字段。
5)sequence 這個字段包含乙個序號
ping命令的實現是使用icmp中型別值為8(reply)和0(request)
現在開始編寫**:
一、解析引數
var (
icmp icmp
laddr = net.ipaddr
//raddr, _ = net.resolveipaddr("ip", os.args[1])
num int
timeout int64
size int
stop bool
)func parseargs()
二、定義icmp結構體
type icmp struct
三、為icmp變數設定值
//icmp頭部填充
icmp.type = 8
icmp.code = 0
icmp.checksum = 0
icmp.identifier = 1
icmp.sequencenum = 1
四、計算icmp校驗和
這邊講解下校驗和的計算,icmp的校驗和ip的校驗不同,icmp的校驗是校驗icmp頭部和資料內容,icmp校驗和計算過程如下:
1)將icmp頭部內容中的校驗內容(checksum)的值設為0
2)將拼接好(type+code+checksum+id+seq+傳輸data)的icmp包按type開始每兩個位元組一組(其中checksum的兩個位元組都看成0),進行加和處理,如果位元組個數為奇數個,則直接加上這個位元組內容。說明:這個加和過程的內容放在乙個4位元組上,如果溢位4位元組,則將溢位的直接拋棄
3)將高16位與低16位內容加和,直到高16為0
4)將步驟三得出的結果取反,得到的結果就是icmp校驗和的值
驗證校驗和的方式也是一樣,驗證時先計算驗證和,然後和驗證和中內容進行比較是否一樣
func checksum(data byte) uint16
if length == 1
sum = uint16(sum >> 16) + uint16(sum)
sum = uint16(sum >> 16) + uint16(sum)
return uint16(^sum)
}
五、傳送icmp包
六、列印結果
package main
import (
"bytes"
"encoding/binary"
"flag"
"fmt"
"log"
"net"
"os"
"time"
"math"
)type icmp struct
var (
icmp icmp
laddr = net.ipaddr
num int
timeout int64
size int
stop bool
)func main()
desip := args[len(args) - 1]
conn, err := net.dialtimeout("ip:icmp", desip, time.duration(timeout) * time.millisecond)
if err != nil
defer conn.close()
//icmp頭部填充
icmp.type = 8
icmp.code = 0
icmp.checksum = 0
icmp.identifier = 1
icmp.sequencenum = 1
fmt.printf("\n正在 ping %s 具有 %d 位元組的資料:\n", desip, size)
var buffer bytes.buffer
binary.write(&buffer, binary.bigendian, icmp) // 以大端模式寫入
data := make(byte, size) //
buffer.write(data)
data = buffer.bytes()
var successtimes int // 成功次數
var failtimes int // 失敗次數
var mintime int = int(math.maxint32)
var maxtime int
var totaltime int
for i := 0;i < num;i++
buf := make(byte, 65535)
n, err = conn.read(buf)
if err != nil
et := int(time.since(t1) / 1000000)
if mintime > et
if maxtime 1
if length == 1
// checksum的值是16位,計算是將高16位加低16位,得到的結果進行重複以該方式進行計算,直到高16位為0
/*sum的最大情況是:ffffffff
第一次高16位+低16位:ffff + ffff = 1fffe
第二次高16位+低16位:0001 + fffe = ffff
即推出乙個結論,只要第一次高16位+低16位的結果,再進行之前的計算結果用到高16位+低16位,即可處理溢位情況
*/sum = uint32(sum >> 16) + uint32(sum)
sum = uint32(sum >> 16) + uint32(sum)
return uint16(^sum)
}func parseargs()
func usage()
}
參考文章:
1)2)
3)4)
C語言實現ping命令(一)
ping命令使用到了網路中的icmp協議 關於icmp介紹看這裡 網路位址資訊 struct sockaddr in struct in addr struct in addr define in addr t uint32 t 無符號整型32位 還可以使用以下結構體 struct sockaddr...
Go語言實現Valid Parentheses
write a function called that takes a string of parentheses,and determines if the order of the parentheses is valid.the function should return true if ...
如何使用Go語言實現遠端執行命令
前言 遠端執行命令有什麼用?為什麼要遠端執行命令wgrgtkdtxn?如果你只有2,3臺伺服器需要管理的時候,遠端執行命令確實沒有沒多大作用,你可以登入到每台伺服器上去完成各種操作。當你的伺服器大於3臺的時候,遠端執行的命令的方式就可以大大提高你的生產力了。如果你有乙個可以遠端執行命令的工具,那麼就...