2012-12-11 4 views
10

Sto usando mono per creare un programma C# che deve inviare e ricevere usando UDP. Attualmente la mia implementazione funziona come previsto su Windows ma ho problemi a far funzionare la comunicazione con i miei sistemi Ubuntu o Fedora.UDP in C# funziona su Windows ma non su Linux

Windows può trasmettere e ricevere i propri datagrammi.
Ubuntu può trasmettere e ricevere i propri datagrammi. Le trasmissioni sono ricevute da Windows ma non vede i datagrammi trasmessi da Windows.
Fedora può trasmettere ma non riceve datagrammi da nessuna parte (nemmeno da solo). Le trasmissioni sono ricevute da Windows.

Quando i datagrammi non riescono a raggiungere una delle macchine linux, la funzione "ricezione" non viene mai attivata.

Questo è quello che ho finora:

int _port = 4568; 
var server = new UdpClient(_port); 
var send_UDP = new UdpClient(); 

La ricezione metodo utilizza le chiamate asincrone della classe UdpClient;

private static void receive() 
{ 
    server.BeginReceive(new AsyncCallback(receive), null); 
} 
private static void receive(IAsyncResult o) 
{   
    try 
    { 
     // I'm told that port = 0 should receive from any port. 
     var sender = new IPEndPoint(IPAddress.Any, 0); 
     var data = server.EndReceive(o, ref sender); 
     receive(); 
     var str = new string(Encoding.ASCII.GetChars(data)); 
     postmessage(sender.Address.ToString() + ":" + sender.Port.ToString() + " > " + str); 
    } 
    catch {} 
} 

E il metodo di invio;

public static void send(string message) 
{ 
    var target = new IPEndPoint(IPAddress.Parse("255.255.255.255"), _port); 
    byte[] data = Encoding.ASCII.GetBytes(message); 
    send_UDP.Send(data, data.Length, target); 
} 

Dopo alcuni test con Fedora, sembra essere un problema con l'uso di 255.255.255.255 per trasmettere. C'è un altro modo per farlo?

+4

si ottiene errori? Hai provato a rimuovere il 'try-catch' per vedere se ci sono errori di runtime? Hai impostato un punto di interruzione in 'receive' per vedere se viene chiamato? –

+0

Il 'try-catch' è solo per ricevere da più utenti - nel mio codice di debug l'eccezione viene stampata sulla console. Proverò a eseguire il debug del metodo di ricezione sugli altri sistemi (non era qualcosa che avevo pensato di provare). –

+0

Il codice di ricezione non viene mai attivato su Fedora. Questo sembra essere indipendente da dove ha origine il datagramma (ho provato a inviare dal computer locale e da una finestra di Windows). –

risposta

2

Ho già specificato questo in un commento ma ponendo questo come una risposta in quanto potresti averlo trascurato e nessuna risposta sembra essere imminente.

Invece di utilizzare 255.255.255.255 per la trasmissione, utilizzare l'indirizzo di trasmissione della subnet IP locale (ad esempio 192.168.0.255 su una subnet 192.168.0.1/24). L'indirizzo 255.255.255.255 non verrà inoltrato da un router (ciò è rilevante se ci sono più sottoreti nei siti dei tuoi clienti) mentre una trasmissione diretta può essere inoltrata (se così configurato). Prima era il caso che i router inoltrassero trasmissioni dirette per default, ma questo era cambiato in RFC2644 quindi non scommettere la fattoria su di esso;).

Ecco un esempio di calcolo l'indirizzo di broadcast IPV4 diretto per adattatore:

public static void DisplayDirectedBroadcastAddresses() 
{ 

    foreach (var iface in NetworkInterface.GetAllNetworkInterfaces() 
      .Where(c => c.NetworkInterfaceType != NetworkInterfaceType.Loopback)) 
    { 
     Console.WriteLine(iface.Description); 
     foreach (var ucastInfo in iface.GetIPProperties().UnicastAddresses 
       .Where(c => !c.Address.IsIPv6LinkLocal)) 
     { 
      Console.WriteLine("\tIP  : {0}", ucastInfo.Address); 
      Console.WriteLine("\tSubnet : {0}", ucastInfo.IPv4Mask); 
      byte[] ipAdressBytes = ucastInfo.Address.GetAddressBytes(); 
      byte[] subnetMaskBytes = ucastInfo.IPv4Mask.GetAddressBytes(); 

      if (ipAdressBytes.Length != subnetMaskBytes.Length) continue; 

      var broadcast = new byte[ipAdressBytes.Length]; 
      for (int i = 0; i < broadcast.Length; i++) 
      { 
       broadcast[i] = (byte)(ipAdressBytes[i] | ~(subnetMaskBytes[i])); 
      } 
      Console.WriteLine("\tBroadcast: {0}", new IPAddress(broadcast).ToString()); 
     } 
    } 

}