在localhost上丢失了很多udp数据包

时间:2014-02-19 17:55:01

标签: c# sockets udp udpclient

我使用此代码接收扫描线:

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();
        }
    }

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

这应该可行,但即使在localhost上也有很多丢失的数据包(只有~95的480),所以我有条纹图像。我发现了类似的问题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);
        }
    }
}

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

1 个答案:

答案 0 :(得分:1)

UDP不保证将收到所有数据包,它们将以任何特定顺序到达。因此,即使你让这个“工作”意识到它可能(很可能)在某些时候失败。

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

其他一些说明:

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

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

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

你失踪的Fire ...方法可能只是引发(触发)一个事件来告诉客户数据已经到达。这是你应该抓住收到的数据并用它做一些事情的地方。

如果您使用示例来构建此代码,那么我建议您寻找更好的示例。 (在任何情况下,我总是建议尝试找到3个例子,这样你就可以比较实现,因为你通常会以这种方式学到很多东西)