无阻塞以太网捕获
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 一个通道,您可以在两个通道上采用 select
ing 的常用策略——对其中一个通道的操作由超时控制。
在最简单的情况下,可以这样做:
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.
我使用这段代码来捕获以太网数据包:
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 anio.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 一个通道,您可以在两个通道上采用 select
ing 的常用策略——对其中一个通道的操作由超时控制。
在最简单的情况下,可以这样做:
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.