无阻塞以太网捕获

No blocking Eternet capture

我使用这段代码来捕获以太网数据包:

var snapshotLen int32 = 102400
var promiscuous bool = true
var timeout time.Duration = 1 * time.Second
var handle *pcap.Handle
handle, err = pcap.OpenLive(device, snapshotLen, promiscuous, timeout)
err = handle.SetBPFFilter(filter)

packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
for packet := range packetSource.Packets() {

}

问题是 packetSource.Packets() 阻塞:如果没有收到数据包,就会出现无限循环。如何设置超时?

来自the docs

func (p *PacketSource) Packets() chan Packet

Packets returns a channel of packets, allowing easy iterating over packets. Packets will be asynchronously read in from the underlying PacketDataSource and written to the returned channel. If the underlying PacketDataSource returns an io.EOF error, the channel will be closed. If any other error is encountered, it is ignored.

for packet := range packetSource.Packets() {   handlePacket(packet) 
// Do something with each packet. }

If called more than once, returns the same channel.

因此,由于 gopacket.PacketSource.Packets() returns 一个通道,您可以在两个通道上采用 selecting 的常用策略——对其中一个通道的操作由超时控制。

在最简单的情况下,可以这样做:

timer := time.NewTicker(2 * time.Second)
defer timer.Stop()

src := gopacket.NewPacketSource(handle, handle.LinkType())
for {
    select {
        case pkt := <- src.Packets():
            // process a packet in pkt
        case <- timer.C:
            // timed out waiting for 2 seconds
    }
}

根据具体的用例,第二个通道可以来自另一个来源——例如 context.