Golang接收ICMP数据包吞吐量低的问题

Golang接收ICMP数据包吞吐量低的问题 我正在尝试使用Go语言并行ping尽可能多的地址。

目前我使用一个Golang程序发送ICMP数据包,另一个程序接收ICMP数据包。发送数据包没有问题,但"接收器"在从套接字读取时会不断"暂停"。

fd, _ := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_ICMP)
f := os.NewFile(uintptr(fd), fmt.Sprintf("fd %d", fd))

i := 0
for {
	buf := make([]byte, 1024)
	numRead, err := f.Read(buf)
	if err != nil {
		fmt.Println(err)
	}
	_ = numRead
	//fmt.Printf("% X\n", buf[:numRead])
	fmt.Println(i)
	i++
}

这段代码大约能读取250个数据包/秒,之后就会忽略大部分数据包。

谢谢


更多关于Golang接收ICMP数据包吞吐量低的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang接收ICMP数据包吞吐量低的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


问题可能出现在使用os.File包装原始套接字进行读取的方式上。原始套接字需要更底层的系统调用处理,而os.File.Read可能引入了不必要的缓冲或系统调用开销。建议直接使用syscall.Read或切换到golang.org/x/net/ipv4包进行更高效的ICMP数据包处理。

以下是改进后的代码示例,使用syscall.Read直接操作文件描述符:

fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_ICMP)
if err != nil {
    panic(err)
}
defer syscall.Close(fd)

i := 0
for {
    buf := make([]byte, 1024)
    numRead, err := syscall.Read(fd, buf)
    if err != nil {
        fmt.Println(err)
        continue
    }
    _ = numRead
    //fmt.Printf("% X\n", buf[:numRead])
    fmt.Println(i)
    i++
}

或者使用golang.org/x/net/ipv4包:

import "golang.org/x/net/ipv4"

conn, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
if err != nil {
    panic(err)
}
defer conn.Close()

p := ipv4.NewPacketConn(conn)
p.SetControlMessage(ipv4.FlagTTL|ipv4.FlagSrc|ipv4.FlagDst|ipv4.FlagInterface, true)

i := 0
buf := make([]byte, 1024)
for {
    n, cm, _, err := p.ReadFrom(buf)
    if err != nil {
        fmt.Println(err)
        continue
    }
    _ = n
    _ = cm
    //fmt.Printf("% X\n", buf[:n])
    fmt.Println(i)
    i++
}

这些方法应该能显著提高ICMP数据包的接收吞吐量。

回到顶部