2012-08-22 2 views
4

제목에 C#의 UDP에 문제가 있다고합니다. DayZ 게임의 rcon 프로토콜 라이브러리를 빌드하려고합니다.모든 패킷이 도착했지만 C# UDP 패킷 손실 (WireShark)

내 문제는 내가 받아야하는 모든 패킷을받지 못한다는 것입니다. 명령을 보낸 후 서버는 분할 답변으로 응답합니다. 패킷 헤더는 총 패킷 수와 현재 패킷의 인덱스를 포함합니다. 이제 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) { } 
       } 
      } 
     } 
    } 
+1

나는 지적인 사람들이 얼마나 많은 사람들이 "느슨한"것이 "잃어 버리는"것과 같은 단어가 아닌지 모를 때 항상 놀란다. –

+1

영어 지식 향상에 도움을 주셔서 감사합니다. – Swarley

+0

'_udpClient.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, 0x40000과 같은 큰 값); –

답변

4

이것은 일반적으로 커널 소켓 버퍼가 가득 차면 네트워크 스택이 도착 새로 놓기 시작, 그래서 당신은 충분히 빨리 당신의 데이터 그램을 소모하지 않기 때문에 패킷. 일부 포인트 : -

  • 비 블로킹을 고려, 다음 큐에 데이터를 당신이 할 수있는만큼 넣어 읽기

    • 모든 반복에 대한 잠금을 획득하지 마십시오 소켓에 수신 버퍼 증가 스레드 대신 접근.
  • +0

    수신 버퍼를 늘리는 것이 효과적입니다. 비 차단으로 BeginReceive & EndReceive가 맞습니까? 그 전에는 사용했지만 테스트 목적으로는 스레드로 전환했습니다. 도와 줘서 고마워! – Swarley

    +0

    아니요, 소켓을 비 블로킹하고 스레드를 없애는 것을 의미합니다. .NET 비동기 콜백은 스레드 풀에서 실행됩니다. –