【问题标题】:C# UDP packetloss though all packets arrive (WireShark)通过所有数据包到达的 C# UDP 数据包丢失 (WireShark)
【发布时间】:2012-08-23 03:38:09
【问题描述】:

正如标题所说,我在 C# 中遇到了 UDP 问题。 我正在尝试为 DayZ 游戏的 rcon 协议构建一个库。

我的问题是我没有收到我应该收到的每个数据包。 发送命令后,服务器回复一个拆分答案。数据包头包含总数据包计数和当前数据包的索引。 现在,如果我应该得到 17 个数据包,我的应用程序中只会得到 8-15 个数据包。

在使用 WireShark 进行测试后,我现在知道所有包裹都到达了我的计算机上。他们只是没有被我的应用程序或类似的东西识别。

我的实际问题是: 是否可以防止丢失我的网卡和我的应用程序之间的包?或者 为什么会这样?

这是我当前的代码。它很脏,因为我在没有按预期工作后把它撕开了:

    private Socket _udpClient;
    private Thread _receiverThread;
    private Thread _workerThread;
    private Queue<byte[]> _packetQueue;
    private PacketBuffer[] MessageBuffer;
    private byte SenderSequence = 0;
    private IPEndPoint connection;

    public RCon(IPAddress ip, int port)
    {
        connection = new IPEndPoint(ip, port);
        _udpClient = new Socket(connection.Address.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
        _udpClient.Connect(connection);
        MessageBuffer = new PacketBuffer[256];
        _packetQueue = new Queue<byte[]>();

        _receiverThread = new Thread(new ThreadStart(ReceiveCallback));
        _receiverThread.IsBackground = true;
        _receiverThread.Priority = ThreadPriority.AboveNormal;
        _receiverThread.Start();
        _workerThread = new Thread(new ThreadStart(WorkerCallback));
        _workerThread.IsBackground = true;
        _workerThread.Start();
    }

    public void Login(string password)
    {
        LoginPacket packet = new LoginPacket(password);

        _udpClient.Send(packet.Bytes);
    }

    public void SendCommand(string command)
    {
        CommandPacket packet = new CommandPacket(SenderSequence, command);
        SenderSequence++;

        _udpClient.Send(packet.Bytes);
    }

    private void ReceiveCallback()
    {

        while (true)
        {
                byte[] buffer = new byte[1036];
                if (_udpClient.Receive(buffer) > 0)
                    _packetQueue.Enqueue(buffer);
        }
    }

    private void WorkerCallback()
    {
        while (true)
        {
            if (_packetQueue.Count > 0)
            {
                byte[] buffer = _packetQueue.Dequeue();

                if (buffer != null)
                {
                    try
                    {
                        Packet receivedPacket = Packet.ParseIncoming(buffer);

                        OnPacketReceived(new PacketReceivedEventArgs(receivedPacket));

                        switch (receivedPacket.Type)
                        {
                            case PacketType.Message:
                                OnMessageReceived(new MessageReceivedEventArgs(receivedPacket.Content));
                                MessageCallbackPacket packet = new MessageCallbackPacket(receivedPacket.SequenceNumber);
                                _udpClient.Send(packet.Bytes);
                                break;
                            case PacketType.CommandCallback:
                                if (MessageBuffer[receivedPacket.SequenceNumber] == null)
                                    MessageBuffer[receivedPacket.SequenceNumber] = new PacketBuffer(receivedPacket);
                                else
                                    MessageBuffer[receivedPacket.SequenceNumber].AddPacket(receivedPacket);

                                if (MessageBuffer[receivedPacket.SequenceNumber].IsComplete)
                                    OnCommandCallback(new CommandCallbackEventArgs(MessageBuffer[receivedPacket.SequenceNumber].GetContent()));
                                break;
                        }
                    }
                    catch (ArgumentException) { }
                    catch (OverflowException) { }
                    catch (FormatException) { }
                }
            }
        }
    }

【问题讨论】:

  • 我总是惊讶于有多少聪明人不知道“松散”与“失去”是同一个词。
  • 感谢您帮助我增加英语知识。
  • _udpClient.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, a big value like 0x40000);

标签: c# .net networking udp


【解决方案1】:

这通常是因为您使用数据报的速度不够快,因此内核套接字缓冲区已满,网络堆栈开始丢弃新到达的数据包。几点:

  • 增加套接字上的接收缓冲区,
  • 不要在每次迭代时都获取锁 - 尽可能多地读取,然后将数据放入队列中,
  • 考虑使用非阻塞方法而不是线程。

【讨论】:

  • 增加接收缓冲区对我有用。非阻塞是指 BeginReceive 和 EndReceive 对吗?我之前使用过,但为了测试目的切换到线程。感谢您的帮助!
  • 不,我的意思是非阻塞套接字并取消线程。 .NET 异步回调在线程池中运行。
  • 从哪里可以确认接收缓冲区是实际问题?我正在使用 WS 2016,默认缓冲区大小为 8 KB,并将缓冲区大小增加到 2 MB,但在我的情况下仍然没有任何区别。
  • @Girish,检查 Socket.Available 属性并确保它小于缓冲区大小
猜你喜欢
  • 2014-12-19
  • 2012-10-01
  • 2019-04-26
  • 2015-06-30
  • 1970-01-01
  • 2018-06-22
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
相关资源
最近更新 更多