Как получить непрерывный пакет по Sharppcap? - PullRequest
0 голосов
/ 09 июля 2019

В настоящее время я пытаюсь перехватить пакет EtherCAT, отправленный и полученный через программу TwinCAT.TwinCAT - это программа управления в реальном времени для обмена данными EtherCAT в Windows.Эта программа используется для связи с рабами каждые 4 мс.

Кстати, я захватил пакеты и заметил, что данные не были непрерывными во время анализа.Итак, я вставил код для проверки разницы во времени в части захвата пакета, и было подтверждено, что некоторые пакеты являются пакетами на 20 мс позже, чем предыдущий пакет.

Поскольку я могу проверить потерянный кадр в 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 Ответ

0 голосов
/ 09 июля 2019

Если вы программируете это не просто для удовольствия или для образовательных целей, а для профессионального использования, я предлагаю вам проанализировать пакеты Ethercat ваших машин с помощью Wireshark и дополнительного оборудования под названием ET2000.

ET2000добавляет метку времени с макс.задержка 40 нс для зеркального пакета, отправленного на ПК, который вы сможете прочитать благодаря анализатору EtherCAT Stack Link в wireshark.

...