Sharppcap如何获取连续数据包?
How to get continuous packet by Sharppcap?
我目前正在尝试捕获通过名为 TwinCAT 的程序发送和接收的 EtherCAT 数据包。
TwinCAT 是用于 Windows 上 EtherCAT 通信的实时控制软件。该程序用于每4ms与slave通信。
顺便抓包,分析的时候发现数据不是连续的。
于是,我在抓包的部分插入了检查时间差的代码,确认有些包是比上一个包晚了20ms的包。
由于我可以在TwinCAT XAE Tool中检查Lost Frame,所以我认为数据包实际上并没有丢失,我认为我的程序有问题。
下面是我的代码。
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 毫秒或更多的差异,则通过抛出异常来检测问题。
这是因为我的表现不好导致的问题吗?
性能提升能解决吗?
如果您有好的意见,请回复。
如果您不是为了娱乐或出于教育目的而编写此程序,而是为了专业用途,我建议您使用 Wireshark 和一个名为 ET2000 的附加硬件分析您机器的 Ethercat 数据包。
ET2000 增加了时间戳,最大。 40ns 的延迟,到发送到 pc 的镜像数据包,由于 EtherCAT Stack Link wireshark 中的解析器,您将能够读取它。
我们在 EtherCAT 和 PROFINET 捕获方面遇到了类似的问题。我们从那时起就使用 Hilscher netANALYZER 工具,现在一切都很好。这些工具内置了硬件 TAP,因此延迟更小 1 ns。时间戳分辨率也是 1 ns。
我目前正在尝试捕获通过名为 TwinCAT 的程序发送和接收的 EtherCAT 数据包。 TwinCAT 是用于 Windows 上 EtherCAT 通信的实时控制软件。该程序用于每4ms与slave通信。
顺便抓包,分析的时候发现数据不是连续的。 于是,我在抓包的部分插入了检查时间差的代码,确认有些包是比上一个包晚了20ms的包。
由于我可以在TwinCAT XAE Tool中检查Lost Frame,所以我认为数据包实际上并没有丢失,我认为我的程序有问题。
下面是我的代码。
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 毫秒或更多的差异,则通过抛出异常来检测问题。
这是因为我的表现不好导致的问题吗? 性能提升能解决吗? 如果您有好的意见,请回复。
如果您不是为了娱乐或出于教育目的而编写此程序,而是为了专业用途,我建议您使用 Wireshark 和一个名为 ET2000 的附加硬件分析您机器的 Ethercat 数据包。
ET2000 增加了时间戳,最大。 40ns 的延迟,到发送到 pc 的镜像数据包,由于 EtherCAT Stack Link wireshark 中的解析器,您将能够读取它。
我们在 EtherCAT 和 PROFINET 捕获方面遇到了类似的问题。我们从那时起就使用 Hilscher netANALYZER 工具,现在一切都很好。这些工具内置了硬件 TAP,因此延迟更小 1 ns。时间戳分辨率也是 1 ns。