我正在制作一个ping库,主要是为了好玩。制作ping库。我应该遵循实际的ping行为吗?
我最近在我的实现中发现了一个错误,我没有检查收到的打包seq。如果发生超时,我现在通过丢弃数据包来修复它。
但今天,我看到ping实用程序打印收到的回复数据包,即使它们超时。
Request timeout for icmp_seq 2
Request timeout for icmp_seq 3
64 bytes from 80.67.169.18: icmp_seq=2 ttl=58 time=2216.104 ms
64 bytes from 80.67.169.18: icmp_seq=3 ttl=58 time=1216.559 ms
我不知道我的图书馆应该做什么。我是否应该保持实际行为,还是需要将其调整为“旧”ping方式?
/*
Package libping provide the ability to send ICMP packets easily.
*/
package libping
import (
"bytes"
"net"
"os"
"time"
)
const (
ICMP_ECHO_REQUEST = 8
ICMP_ECHO_REPLY = 0
)
// The struct Response is the data returned by Pinguntil.
type Response struct {
Delay time.Duration
Error error
Destination string
Seq int
Readsize int
Writesize int
}
func makePingRequest(id, seq, pktlen int, filler []byte) []byte {
p := make([]byte, pktlen)
copy(p[8:], bytes.Repeat(filler, (pktlen-8)/len(filler)+1))
p[0] = ICMP_ECHO_REQUEST // type
p[1] = 0 // code
p[2] = 0 // cksum
p[3] = 0 // cksum
p[4] = uint8(id >> 8) // id
p[5] = uint8(id & 0xff) // id
p[6] = uint8(seq >> 8) // sequence
p[7] = uint8(seq & 0xff) // sequence
// calculate icmp checksum
cklen := len(p)
s := uint32(0)
for i := 0; i < (cklen - 1); i += 2 {
s += uint32(p[i+1])<<8 | uint32(p[i])
}
if cklen&1 == 1 {
s += uint32(p[cklen-1])
}
s = (s >> 16) + (s & 0xffff)
s = s + (s >> 16)
// place checksum back in header; using ^= avoids the
// assumption the checksum bytes are zero
p[2] ^= uint8(^s & 0xff)
p[3] ^= uint8(^s >> 8)
return p
}
func parsePingReply(p []byte) (id, seq, code int) {
id = int(p[24])<<8 | int(p[25])
seq = int(p[26])<<8 | int(p[27])
code = int(p[21])
return
}
// Pingonce send one ICMP echo packet to the destination, and return the latency.
// The function is made to be simple. Simple request, simple reply.
func Pingonce(destination string) (time.Duration, error) {
response := make(chan Response)
go Pinguntil(destination, 1, response, time.Second)
answer := <-response
return answer.Delay, answer.Error
}
// Pinguntil will send ICMP echo packets to the destination until the counter is reached, or forever if the counter is set to 0.
// The replies are given in the Response format.
// You can also adjust the delay between two ICMP echo packets with the variable delay.
func Pinguntil(destination string, count int, response chan Response, delay time.Duration) {
raddr, err := net.ResolveIPAddr("ip", destination)
if err != nil {
response <- Response{Delay: 0, Error: err, Destination: destination, Seq: 0}
close(response)
return
}
ipconn, err := net.Dial("ip:icmp", raddr.IP.String())
if err != nil {
response <- Response{Delay: 0, Error: err, Destination: raddr.IP.String(), Seq: 0}
close(response)
return
}
sendid := os.Getpid() & 0xffff
pingpktlen := 64
seq := 0
var elapsed time.Duration = 0
for ; seq < count || count == 0; seq++ {
elapsed = 0
if seq > 65535 { // The two bytes for seq. Don't overflow!
seq = 0
}
sendpkt := makePingRequest(sendid, seq, pingpktlen, []byte("Go Ping"))
start := time.Now()
writesize, err := ipconn.Write(sendpkt)
if err != nil || writesize != pingpktlen {
response <- Response{Delay: 0, Error: err, Destination: raddr.IP.String(), Seq: seq, Writesize: writesize, Readsize: 0}
time.Sleep(delay)
continue
}
ipconn.SetReadDeadline(time.Now().Add(time.Second * 1)) // 1 second
resp := make([]byte, 1024)
for {
readsize, err := ipconn.Read(resp)
elapsed = time.Now().Sub(start)
rid, rseq, rcode := parsePingReply(resp)
if err != nil {
response <- Response{Delay: 0, Error: err, Destination: raddr.IP.String(), Seq: seq, Writesize: writesize, Readsize: readsize}
break
} else if rcode != ICMP_ECHO_REPLY || rseq != seq || rid != sendid {
continue
} else {
response <- Response{Delay: elapsed, Error: err, Destination: raddr.IP.String(), Seq: seq, Writesize: writesize, Readsize: readsize}
break
}
}
time.Sleep(delay - elapsed)
}
close(response)
}
该库不是用于specitif用法。我会用它来做一些项目,但我想知道每个选择的参数。
而我看,执行第二个选项将会更困难。
谢谢! (如果我的职位是不明确的,不要犹豫,问我要澄清,这是晚了。)
如果你想检查项目地址:here
我实际上报告超时。我的问题是“我应该报告所有收到的数据包,即使我将它们报告为超时?” – Cubox
是的,否则你会有两种机制将信息传递给用户:1.这是一个数据包; 2.这是一个超时。有一个统一的方式更好:这是一个数据包,它还没有耗尽时间。 – nemo
是的,但重点在于用户将收到“数据包2已超时!”并且在“我们收到了包2!”之后不久 – Cubox