4

タイトルにあるように、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) { }
                }
            }
        }
    }
4

1 に答える 1

4

これは通常、データグラムを十分な速度で消費していないため、カーネル内のソケットバッファがいっぱいになり、ネットワークスタックが新しく到着したパケットをドロップし始めます。いくつかのポイント:

  • ソケットの受信バッファを増やし、
  • 反復ごとにロックを取得しないでください。できるだけ多くのデータを読み取り、データをキューに入れてください。
  • スレッドの代わりにノンブロッキングアプローチを検討してください。
于 2012-08-22T15:45:42.823 に答える