2013-03-18 5 views
1

Я работаю над написанием сетевой библиотеки на C# и изначально использовал .NET 3.5 Framework. Недавно я решил переключиться на .NET 4.5, но столкнулся с проблемой отправки пакетов UDP. То, что я натолкнулся на то, что UDP-пакеты отправляются слишком быстро, метод Socket.SendToAsync завершает работу с SocketErrorAddressFamilyNotSupported и пакеты никогда не отправляются.C# .NET 4.0/4.5 Ошибка отправки UDP

Если я переключу проект на .NET 3.5, я никогда не сталкиваюсь с проблемой, как бы я ни старался повторить ее. Это также можно воспроизвести в .NET 4.0.

Вот link к проекту, который я собрал, чтобы воспроизвести проблему. Если вы спамете кнопки «ClientSnd» или «ServerSnd», вы увидите ошибку. Переключите проект на .NET 3.5 и спам, который вы хотите ... никаких проблем.

Я не смог найти много полезной информации в этом вопросе. Есть идеи?

EDIT (добавлен код из примера проекта записи демо вопрос):

Вот где связывает происходят и для клиента и сервера:

  byte[] clientBuffer = new byte[32768]; 
      byte[] serverBuffer = new byte[32768]; 

      IPEndPoint clientLocalEndPoint = GetLocalIPEndPoint(0, AddressFamily.InterNetwork); 
      IPEndPoint serverLocalEndPoint = GetLocalIPEndPoint(6337, AddressFamily.InterNetwork); 

      m_ClientSocket.ExclusiveAddressUse = true; 
      m_ServerSocket.ExclusiveAddressUse = true; 
      m_ClientSocket.Bind(clientLocalEndPoint); 
      m_ServerSocket.Bind(serverLocalEndPoint); 

      m_ClientSendArgs.RemoteEndPoint = GetRemoteIPEndPoint("127.0.0.1", 6337, AddressFamily.InterNetwork); 
      m_ClientRecvArgs.RemoteEndPoint = m_ClientSocket.LocalEndPoint; 

      m_ServerSendArgs.RemoteEndPoint = GetRemoteIPEndPoint("127.0.0.1", ((IPEndPoint)m_ClientSocket.LocalEndPoint).Port, AddressFamily.InterNetwork); 
      m_ServerRecvArgs.RemoteEndPoint = m_ServerSocket.LocalEndPoint; 

      m_ClientSendArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnClientCompletion); 
      m_ClientRecvArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnClientCompletion); 
      m_ServerSendArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnServerCompletion); 
      m_ServerRecvArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnServerCompletion); 

      m_ClientRecvArgs.SetBuffer(clientBuffer, 0, clientBuffer.Length); 
      m_ServerRecvArgs.SetBuffer(serverBuffer, 0, serverBuffer.Length); 

      ClientReceive(); 
      ServerReceive(); 

В GetRemoteIPEndPoint и GetLocalIPEndPoint методы:

private static IPEndPoint GetRemoteIPEndPoint(string address, int port, AddressFamily addressFamily) 
    { 
     IPAddress[] ipAddresses = null; 

     ipAddresses = Dns.GetHostAddresses(address); 

     List<IPEndPoint> ipEndPointList = new List<IPEndPoint>(); 

     for (int i = 0; i < ipAddresses.Length; i++) 
     { 
      IPAddress ipAddress = ipAddresses[i]; 

      if (ipAddress.AddressFamily == addressFamily) 
      { 
       IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, port); 

       ipEndPointList.Add(ipEndPoint); 
      } 
     } 

     return ipEndPointList.ToArray()[0]; 
    } 

    private static IPEndPoint GetLocalIPEndPoint(int port, AddressFamily addressFamily) 
    { 
     IPEndPoint localEndPoint = null; 

     switch (addressFamily) 
     { 
      case AddressFamily.InterNetwork: 
       { 
        localEndPoint = new IPEndPoint(IPAddress.Any, port); 

        break; 
       } 
      case AddressFamily.InterNetworkV6: 
       { 
        localEndPoint = new IPEndPoint(IPAddress.IPv6Any, port); 

        break; 
       } 
     } 

     return localEndPoint; 
    } 

Поскольку это происходит, регар dless кто отправляет данные (клиента или сервера), я сосредоточусь на клиенте является отправитель:

ClientSnd Нажатие кнопки:

private void Button_ClientSnd_Click(object sender, RoutedEventArgs e) 
    { 
     lock (SyncRoot) 
     { 
      byte[] buffer = Encoding.ASCII.GetBytes("Hello there. Just testing. Nothing to see here. Move along."); 

      m_ClientSendQueue.Enqueue(buffer); 

      if (!m_ClientTransmitting) 
      { 
       m_ClientTransmitting = true; 

       ClientSendBuffer(); 
      } 
     } 
    } 

методы передачи для клиента:

private void ClientSendBuffer() 
    { 
     lock (SyncRoot) 
     { 
      if (m_ClientSendQueue.Count > 0) 
      { 
       byte[] buffer = m_ClientSendQueue.Dequeue(); 

       m_ClientSendArgs.SetBuffer(buffer, 0, buffer.Length); 

       ClientSend(); 
      } 
      else 
      { 
       m_ClientTransmitting = false; 
      } 
     } 
    } 

    private void ClientSend() 
    { 
     if (!m_ClientSocket.SendToAsync(m_ClientSendArgs)) 
     { 
      OnClientCompletion(this, m_ClientSendArgs); 
     } 
    } 

Завершение обратного вызова для клиента:

private void OnClientCompletion(object sender, SocketAsyncEventArgs e) 
    { 
     SocketError socketError = e.SocketError; 

     if (socketError != SocketError.Success) 
     { 
      ClientConsoleWrite("SocketError: {0}\r\n", socketError); 
     } 

     switch (e.LastOperation) 
     { 
      case SocketAsyncOperation.SendTo: 
       { 
        if (socketError == SocketError.Success) 
        { 
         ClientConsoleWrite("Client message sent!\r\n"); 
        } 

        ClientSendBuffer(); 

        break; 
       } 
      case SocketAsyncOperation.ReceiveFrom: 
       { 
        int bytesTransferred = e.BytesTransferred; 

        byte[] buffer = new byte[bytesTransferred]; 

        Buffer.BlockCopy(e.Buffer, e.Offset, buffer, 0, bytesTransferred); 

        string message = Encoding.ASCII.GetString(buffer); 

        ClientConsoleWrite("Message received: {0}\r\n", message); 

        ClientReceive(); 

        break; 
       } 
     } 
    } 
+2

Не могли бы вы разместить соответствующие фрагменты на свой вопрос. У многих людей нет времени на загрузку, извлечение и запуск примерного проекта. В основном вы можете указать, где вы указываете адрес в вашем примере кода? –

+0

Я понимаю. Я опубликовал соответствующие фрагменты моего вопроса. –

+0

в GetRemoteIPEndPoint у вас есть 'catch {}', почему вы выбрасываете все свои исключения? Вероятно, вы совершили исключение, пропустили его и вернули null для адреса. Удалите этот try-catch и посмотрите, какую ошибку вы получите. –

ответ

2

я понял это из. Эта проблема происходит потому, что основной буфер на переменной m_ClientSendArgs постоянно изменяется с помощью SetBuffer:

byte[] buffer = m_ClientSendQueue.Dequeue(); 

m_ClientSendArgs.SetBuffer(buffer, 0, buffer.Length); 

Когда я назначен статический буфер для него и использовать Buffer.BlockCopy, вопрос ушел:

byte[] buffer = m_ClientSendQueue.Dequeue(); 

Buffer.BlockCopy(buffer, 0, m_ClientSendBuffer, 0, buffer.Length); 

m_ClientSendArgs.SetBuffer(0, buffer.Length); 

Так что я все время применял это неправильно. Странно, что это не проблема .NET 3.5 или проблема для TCP на .NET 4.0/4.5.

Смежные вопросы