如何通过Sharppcap获得连续数据包?

Posted

技术标签:

【中文标题】如何通过Sharppcap获得连续数据包?【英文标题】:How to get continuous packet by Sharppcap? 【发布时间】:2019-11-18 18:10:31 【问题描述】:

我目前正在尝试捕获通过名为 TwinCAT 的程序发送和接收的 EtherCAT 数据包。 TwinCAT 是 Windows 上用于 EtherCAT 通信的实时控制软件。该程序用于每 4ms 与从机通信。

顺便说一句,我捕获了数据包并观察到数据在分析过程中不连续。 于是,我在抓包部分插入了代码检查时间差,确认有的包比上一个包晚了20ms。

由于我可以在 TwinCAT XAE 工具中检查丢失的帧,我认为数据包实际上并没有丢失,我认为我的程序有问题。

下面是我的代码。

public class EtherCATPacketCaptureService

    private const int PacketQueueSize = 1024;

    private object locker;  //<-Mutex
    private Queue<RawCapture> PacketQueue;  //<-패킷을 저장할 큐
    private WinPcapDevice _etherCATDevice;  //<-EtherCAT 통신 네트워크 장치

    public int PacketsCount  get => PacketQueue.Count; 

    //생성자 : _etherCATDevice 객체와 EtherCAT통신장치 매칭 
    public EtherCATPacketCaptureService(string etherCATNICAddr)
    
        CaptureDeviceList devices = CaptureDeviceList.Instance;

        if (devices.Count() < 1)
        
            throw new Exception("Not exist network interface");
        

        foreach (WinPcapDevice dev in devices)
        
            if (dev.Addresses.Count > 0)
            
                foreach (PcapAddress addr in dev.Addresses)
                
                    if (addr.Addr.hardwareAddress != null)
                    
                        string HWAddr = addr.Addr.hardwareAddress.ToString();
                        if (HWAddr == etherCATNICAddr)  // EtherCAT NIC MAC주소를 EtherCATNICAddr파라미터로 넘겨받아 설정
                        
                            _etherCATDevice = dev;
                        
                    
                
            
        

        if (_etherCATDevice == null)
            throw new NullReferenceException("Can't find EtherCAT NIC");
        else
        
            PacketQueue = new Queue<RawCapture>(PacketQueueSize);
            locker = new object();
            _etherCATDevice.OnPacketArrival += Device_OnPacketArrival;
            _etherCATDevice.Open(OpenFlags.Promiscuous, 1000);
        
    

    ~EtherCATPacketCaptureService()
    
        _etherCATDevice.Close();
    

    //패킷 캡쳐 시작
    public void StartCapture(int timeout)
    
        if(_etherCATDevice != null)
        
            _etherCATDevice.StartCapture();
        
    

    //패킷 캡쳐 종료
    public void StopCapture()
    
        if (_etherCATDevice != null)
        
            _etherCATDevice.StopCapture();
        
    

    //패킷캡쳐 이벤트 발생 시 패킷을 큐메모리에 저장
    private void Device_OnPacketArrival(object sender, SharpPcap.CaptureEventArgs e)
    
        if (_etherCATDevice != null)
        
            lock (locker)
            
                if (PacketQueue != null)
                
                    if (PacketQueue.Count > 0)
                    
                        if((e.Packet.Timeval.Date.Ticks - PacketQueue.Peek().Timeval.Date.Ticks) > 200000)
                            throw new Exception("Packet Droped");
                    
                    PacketQueue.Enqueue(e.Packet);
                
            
        
    

    //저장된 패킷을 리턴(Dequeue)
    public RawCapture[] GetPackets(int count)
    
        RawCapture[] PacketArray;
        if (_etherCATDevice != null)
        
            lock (locker)
            
                if (count >= PacketQueue.Count)
                    PacketArray = new RawCapture[PacketQueue.Count];
                else
                    PacketArray = new RawCapture[count];

                for (int i = 0; i < PacketArray.Length; i++)
                
                    PacketArray[i] = PacketQueue.Dequeue();
                
            
            return PacketArray;
        
        else
            return null;
    

    public RawCapture[] GetPackets()
    
        RawCapture[] PacketArray;
        if (_etherCATDevice != null)
        
            lock (locker)
            
                PacketArray = new RawCapture[PacketQueue.Count];

                for (int i = 0; i < PacketArray.Length; i++)
                
                    PacketArray[i] = PacketQueue.Dequeue();
                
            
            return PacketArray;
        
        else
            return null;
    

    //저장된 패킷 클리어
    public void ClearPackets()
    
        lock (locker)
        
            PacketQueue.Clear();
        
    

OnPacketArrival 的事件处理程序是 Device_OnPacketArrival,如果它发现处理程序中的时间与前一个数据包的时间相比有 20 毫秒或更多的差异,则通过引发异常来检测问题。

这是因为我的表现不好而发生的问题吗? 性能改进可以解决吗? 如果您有好的意见,请回复。

【问题讨论】:

【参考方案1】:

如果您不是出于娱乐或教育目的而编写此程序,而是出于专业用途,我建议您使用 Wireshark 和称为 ET2000 的附加硬件来分析您机器的 Ethercat 数据包。

ET2000 增加了一个时间戳,最大值。 40ns 的延迟,到发送到 pc 的镜像数据包,由于wireshark 中的 EtherCAT Stack Link 解析器,您将能够读取该数据包。

【讨论】:

【参考方案2】:

我们在 EtherCAT 和 PROFINET 捕获方面遇到了类似的问题。从那时起,我们在哪里使用 Hilscher netANALYZER 工具,现在一切都很好。这些工具内置了硬件 TAP,因此延迟更小 1 ns。时间戳分辨率也是 1 ns。

【讨论】:

以上是关于如何通过Sharppcap获得连续数据包?的主要内容,如果未能解决你的问题,请参考以下文章

SharpPcap - 传入的数据包被丢弃

SharpPcap 中的离线数据包过滤

Pcap.net vs Sharppcap

.net 数据包捕获:pcap.net 与 Sharppcap

如何编写 http 隧道

如何通过多个连续的类从一个活动/类传递多个包,以便数据以最终类结束?