【问题标题】:Lost a lot of udp packets on localhost在本地主机上丢失了很多 udp 数据包
【发布时间】:2014-02-19 17:55:00
【问题描述】:

我用这个代码来接收扫描线:

StateObject stateobj = (StateObject)ar.AsyncState;
stateobj.workSocket.BeginReceive(new System.AsyncCallback(VideoReceive), stateobj);
UdpClient client = stateobj.workSocket;

IPEndPoint ipendp = new IPEndPoint(IPAddress.Any, 0);
byte[] data = client.EndReceive(ar, ref ipendp);


    BinaryReader inputStream = new BinaryReader(new MemoryStream(data));
    inputStream.BaseStream.Position = 0;
    int currentPart = inputStream.ReadInt32();


    if (currentPart == part)
    {
        int a = 0;
        int colum = inputStream.ReadInt32();
        for (; a < packets.GetLength(1); a++)
        {
            packets[colum, a, 2] = inputStream.ReadByte();
            packets[colum, a, 1] = inputStream.ReadByte();
            packets[colum, a, 0] = inputStream.ReadByte();
        }
        receiverCheck++;

    }
    else if (currentPart != part)
    {

        part++;
        mask2.Data = packets;

        pictureBox1.BeginInvoke(new MethodInvoker(() => { pictureBox1.Image = mask2.ToBitmap(); }));
        int colum = inputStream.ReadInt32();
        for (int a = 0; a < packets.GetLength(1); a++)
        {
            packets[colum, a, 2] = inputStream.ReadByte();
            packets[colum, a, 1] = inputStream.ReadByte();
            packets[colum, a, 0] = inputStream.ReadByte();
        }
    }

接收到所有扫描线后,pictureBox 中显示的图像。

这应该可以,但是即使在本地主机上也会丢失很多数据包(480 个中只有 95 个),所以我有条纹图像。我发现了一个类似的问题here。 答:

private void OnReceive(object sender, SocketAsyncEventArgs e)
{
TOP:
    if (e != null)
    {
        int length = e.BytesTransferred;
        if (length > 0)
        {
            FireBytesReceivedFrom(Datagram, length, (IPEndPoint)e.RemoteEndPoint);
        }
        e.Dispose(); // could possibly reuse the args?
    }
    Socket s = Socket;
    if (s != null && RemoteEndPoint != null)
    {
        e = new SocketAsyncEventArgs();
        try
        {
            e.RemoteEndPoint = RemoteEndPoint;
            e.SetBuffer(Datagram, 0, Datagram.Length); // don't allocate a new buffer every time
            e.Completed += OnReceive;
            // this uses the fast IO completion port stuff made available in .NET 3.5; it's supposedly better than the socket selector or the old Begin/End methods
            if (!s.ReceiveFromAsync(e)) // returns synchronously if data is already there
                goto TOP; // using GOTO to avoid overflowing the stack
        }
        catch (ObjectDisposedException)
        {
            // this is expected after a disconnect
            e.Dispose();
            Logger.Info("UDP Client Receive was disconnected.");
        }
        catch (Exception ex)
        {
            Logger.Error("Unexpected UDP Client Receive disconnect.", ex);
        }
    }
}

Answer 有方法 FireBytesReceivedFrom(),但我找不到。如何使用此代码?这段代码有帮助吗?

【问题讨论】:

  • UDP 不保证数据包的传递。在 480 个数据包中,您丢失或收到其中的 95 个?写得模棱两可。
  • @ChrisLaplante 收到 95 个数据包。我认为错误的内存使用或类似的问题。无论如何,我可能有答案,但找不到方法 FireBytesReceivedFrom()。

标签: c# sockets udp udpclient


【解决方案1】:

UDP 不保证所有数据包都会被接收,它会以任何特定的顺序到达。所以即使你得到这个“工作”,也要意识到它可能(可能)在某个时候失败。

当您调用 BeginReceive 时,您将开始同步读取。当数据到达时,您的事件处理程序将被调用,而 然后 您需要调用 EndReceive。目前您正在立即调用 EndReceive,这可能就是出现问题的原因。

其他一些注意事项:

我建议您不要聪明地重复使用缓冲区,因为这可能会导致您在尝试读取数据时覆盖数据而丢失数据。从简单开始,在你运行良好后添加这样的优化。

此外,goto 可能会造成严重破坏。您似乎正在尝试使用它来重试,但此代码正在数据接收事件处理程序中运行。事件处理程序应该以最轻量级的方式处理事件,然后返回,而不是开始循环......尤其是因为这里的循环可能会导致对同一事件处理程序的重入调用。

使用异步通信,您应该开始读取并退出。当您最终收到数据(调用您的事件处理程序)时,抓取它并开始新的异步读取。任何比这更复杂的事情都可能导致问题。

您缺少的 Fire... 方法可能只是引发(触发)一个事件以告诉客户端数据已到达。这是您应该抓取接收到的数据并对其进行处理的地方。

如果您使用示例来构建此代码,那么我建议您寻找更好的示例。 (无论如何,我总是建议您尝试找到 3 个示例,以便您可以比较实现,因为您通常会通过这种方式了解更多信息)

【讨论】:

  • 如果我需要获取数据包,如何不立即调用 EndReceive?你能给我代码示例吗,因为我不擅长英语。所以,在代码中实现你的建议对我来说非常困难。谢谢!
  • 您开始接收。收到数据后,将调用您的事件处理程序。然后调用 EndReceive 完成获取数据。您不能通过调用 EndReceive 来强制数据提前到达,您调用它是为了响应数据到达。
  • 我明白了错误调用endReceive的问题。我应该什么时候调用它以及如何调用它?
  • 我已经解释了何时调用它 - 在您的 DataReceived 事件处理程序中。请阅读文档中的示例作为起点:msdn.microsoft.com/en-us/library/…
  • 哦,是我的错。我的第一个代码块是一个事件处理函数。很抱歉造成混乱!
猜你喜欢
  • 2013-08-31
  • 2019-05-25
  • 1970-01-01
  • 2015-06-30
  • 1970-01-01
  • 2012-03-27
  • 2018-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多