我正在尝试编写一个简单的UDP-to-Chart应用程序(用于
Windows窗体),它将从以太网获取原始数据,并以特定方式将其放入图表.这是我到目前为止:具有两个图表的表单,一个用于接收UDP数据包的线程:
public void serverThread()
{
UdpClient udpClient = new UdpClient(Convert.ToInt16(tbEthPort.Text));
while (_serverWork)
{
try
{
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, Convert.ToInt16(tbEthPort.Text));
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
if (receiveBytes.Length > 0)
for (i = 0; i < receiveBytes.Length; i++)
{
bigDataIn[i] = receiveBytes[i];
}
并绘制第二个图表(以特定方式显示所有数据包内容):
if (graphicOn)
{
for (i = 0; i < 32; i++)
{
graphicData[i + (graphicStep * 32)] = bigDataIn[i * 32 + graphicChan];
}
graphicStep++;
if (graphicStep == 32) graphicStep = 0;
try
{
Invoke(new Action(() => { chartGraphic.Series["DataGraphic"].Points.DataBindXY(graphicEnum, graphicData);
}));
}
catch
{
}
}
和一个带有计时器的主线程来绘制第一个图表.
private void tmrHisto_Tick(object sender, EventArgs e)
{
int[] slice = new int[32];
for (int i = 0; i < 32; i++)
slice[i] = bigDataIn[i + 32 * histogramArrayStep];
histogramArrayStep++;
if (histogramArrayStep == 32) histogramArrayStep = 0;
chartHistogram.Series["DataHistogram"].Points.Clear();
for (int i = 0; i < HISTO_XMAX; i++)
{
chartHistogram.Series["DataHistogram"].Points.AddXY(i, slice[i]);
}
}
一切正常,在我的电脑和其他几个,但当我在旧电脑上启动我的应用程序时,我的应用程序开始丢失数据包.当我开始调用chartGraphic时,数据包丢失开始.我可以看到WireShark中的所有数据包(大约每秒20个)没有任何损失.当定时器间隔设置为50ms而不是150ms时,我遇到了同样的问题,但我不能再增加间隔了.
所以这是我的问题 – 我可以提高图形绘制的速度,并阻止低端PC上的数据包丢失.或者我如何在调试期间模拟低端PC?
最佳答案 调用是阻塞的,因此您的receivethread将等到绘图(DataBindXY)完成.尝试将其移出接收线程.
循环缓冲区看起来很快,但它看起来只保存引用.这没有太大改善.此外,您将从udpClient获取新的缓冲区:Byte [] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);循环缓冲区仅在重用“旧”内存时才有用.
尝试并发队列将数据从接收线程传递到gui-thread / timer.确保重新绑定/绘制在并发队列的锁定之外.现在,您正在获得接收数据报的性能.
更新:
一些伪代码:
背部:
private List<byte[]> datagrams = new List<byte[]>();
public void serverThread()
{
UdpClient udpClient = new UdpClient(Convert.ToInt16(tbEthPort.Text));
while (_serverWork)
{
try
{
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, Convert.ToInt16(tbEthPort.Text));
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
// add to the queue
lock (datagrams)
datagrams.Add(receiveBytes);
}
}
}
GUI:
private Timer timer = new Timer();
public void timer_Tick(object sender, EventArgs e)
{
byte[][] data;
// lock the queue as short as possible. (create a copy with ToArray())
// this way the receive thread can run again..
// this is also know as bulk processing..
lock (datagrams)
{
data = datagrams.ToArray();
datagrams.Clear();
}
// if no packets received, don't update anything
if(data.Length == 0)
return;
// process the received data (multiple datagrams)
for(byte[] item in data)
{
...
}
// Update chart
}
您可以检查队列是否不会变得太大.发生这种情况时,您的队列处理速度太慢.您可以限制itemcount.