I'm using mono to build a C# program that needs to send and receive using UDP. Currently my implementation works as expected on Windows but I have issues getting communication to work with my Ubuntu or Fedora systems.
Windows can broadcast and receive it's own datagrams.
Ubuntu can broadcast and receive it's own datagrams. It's broadcasts are received by Windows but it doesn't see datagrams broadcast by Windows.
Fedora can broadcast but does not receive datagrams from anywhere (not even itself). It's broadcasts are received by Windows.
When datagrams fail to reach either of the linux machines, the 'receive' function is never fired.
This is what I have so far:
int _port = 4568;
var server = new UdpClient(_port);
var send_UDP = new UdpClient();
The receive method uses the asynchronous calls of the 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 {}
}
And the send method;
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);
}
After some testing with Fedora, it seems to be an issue with the use of 255.255.255.255 to broadcast. Is there some other way to do this?
I already specified this in a comment but placing this as an answer since you may have overlooked it and no answers seem to be forthcoming.
Instead of using 255.255.255.255 for broadcast use your local IP subnet's broadcasting address (for instance 192.168.0.255 on a 192.168.0.1/24 subnet). The 255.255.255.255address will not be forwarded by a router (this is relevant if there are multiple subnets at your clients' sites) whereas a directed broadcast can be forwarded (if so configured). It used to be the case that routers would forward directed broadcasts per default but this was changed in RFC2644 so don't bet the farm on it ;).
Here's an example of calculating the directed IPV4 broadcast address per adapter:
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());
}
}
}
Related
I am currently creating an Unity Android application (GearVR) that could receive UDP packets send with broadcast on the Wi-Fi.
Unfortunately I can't receive any packet in my application.
Here is the script which I attached to a 3d game object.
public class UDPSceneScript : MonoBehaviour {
Thread udpListeningThread;
Thread udpSendingThread;
public int portNumberReceive;
UdpClient receivingUdpClient;
private void initListenerThread()
{
portNumberReceive = 5000;
Console.WriteLine("Started on : " + portNumberReceive.ToString());
udpListeningThread = new Thread(new ThreadStart(UdpListener));
// Run in background
udpListeningThread.IsBackground = true;
udpListeningThread.Start();
}
public void UdpListener()
{
receivingUdpClient = new UdpClient(portNumberReceive);
while (true)
{
//Listening
try
{
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
//IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Broadcast, 5000);
// Blocks until a message returns on this socket from a remote host.
byte[] receiveBytes = receivingUdpClient.Receive(ref RemoteIpEndPoint);
if (receiveBytes != null)
{
string returnData = Encoding.ASCII.GetString(receiveBytes);
Console.WriteLine("Message Received" + returnData.ToString());
Console.WriteLine("Address IP Sender" + RemoteIpEndPoint.Address.ToString());
Console.WriteLine("Port Number Sender" + RemoteIpEndPoint.Port.ToString());
if (returnData.ToString() == "TextTest")
{
//Do something if TextTest is received
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
void Start()
{
initListenerThread();
}
}
With the program SocketTest 3.0, I send "TextTest" to the address 255.255.255.255, port 5000
(I also tried by targeting directly the IP of the smartphone, it didn't work either)
Thanks in advance
Ran a quick test on your code and came to conclusion that your client code is fine. Replace all Console.WriteLine with Debug.Log and your will receive the data you are broadcasting. Console.WriteLine doesn't display anything in Unity's console.
If the problem is still there, please understand that some OS will block you from broadcasting to 255.255.255.255. If this is the case then get the IP of the device you are broadcasting from and replace the last octet with 255. Broadcast to that IP Address and that will also work just like 255.255.255.255.
For example, if your IP is 192.168.1.13, replace 13 with 255. You should broadcast to 192.168.1.255 in this case.
Finally, put the code below in your client script to make sure you kill that Thread when you click the Stop button in the Editor or you will have many problems during development.
void OnDisable()
{
if (udpListeningThread != null && udpListeningThread.IsAlive)
{
udpListeningThread.Abort();
}
receivingUdpClient.Close();
}
Apps A and B are both listening to and sending from UDP port 1337 on the same computer.
App A was started first (so it bound to port 1337 first).
When they each send a message to 127.255.255.255:1337 or 255.255.255.255:1337, both apps A and B get the each others' messages, as well as their own echo.
When they each send a message to 127.0.0.1:1337 or 192.168.1.65:1337, a non-broadcast address, only A gets B's message and its own echo. B cannot even hear its own message. (192.168.1.65 is my computer's network IP where both apps are running)
If I stop app A, B can hear its own message. If I start A again, B can hear both messages and A can head nothing.
Why do messages get duplicated when sent to a broadcast IP, whereas they are distributed on a first-come-first-serve basis if they are sent to a non-broadcast address? Is there a why to get a consistent behavior (set some "always-duplicate" flag)?
Here is some C# code that demonstrates this:
public class Program
{
public static void Main()
{
var udp = new Udp("255.255.255.255", 1337);
Task.Run(() =>
{
while (true)
{
Console.WriteLine(udp.Receive());
}
});
Task.Run(() =>
{
while (true)
{
Thread.Sleep(1000);
udp.Send("(((1)))");
}
});
Console.ReadLine();
}
}
public class Udp
{
private readonly UdpClient _sender;
private readonly UdpClient _listener;
public Udp(string address, int port)
{
_sender = new UdpClient(address, port);
_listener = new UdpClient();
_listener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_listener.Client.Bind(new IPEndPoint(IPAddress.Any, port));
}
public string Receive()
{
var _ = null as IPEndPoint;
return $"{Encoding.Default.GetString(_listener.Receive(ref _))} from {_.Address}:{_.Port}";
}
public void Send(string message)
{
var dataAsBytes = Encoding.ASCII.GetBytes(message);
_sender.Send(dataAsBytes, dataAsBytes.Length);
}
}
You can run this app twice, change the number in udp.Send("(((1)))") to identify each. When you use new Udp("255.255.255.255", 1337) both instances can hear both messages, whereas using new Udp("127.0.0.1", 1337) causes the first instance only to be able to pick up messages. Thank you!
I Have two ethernet ports in my system,
and I have configured their IP address as- 10.169.20.15 and 10.169.20.30 respectively. I am trying to transmit UDP frames from one application through port with IP address 10.169.20.30. With another application I am trying to receive the frame through the other ethernet port with IP 10.169.20.15.
While transmitting I am able to set my source IP address( So that the particular ethernet port with that IP is used for transmitting) and my destination IP address.
But for recieving I dont know how to set the port with IP 10.169.20.15 as the recieve port.
Tx code
class Program
{
static IPEndPoint Mypoint = new IPEndPoint(IPAddress.Parse("10.169.20.30"), 8050);// Source IP
static IPEndPoint UrPoint = new IPEndPoint(IPAddress.Parse("10.169.20.15"), 8051);// Destination IP
static UdpClient TxClient;
static void Main(string[] args)
{
int i = 0;
byte [] data= new byte[1472];
TxClient = new UdpClient(Mypoint);
while (i < 500)
{
data[i]++;
try
{
TxClient.Send(data, data.Length, UrPoint);
}
catch { }
Console.WriteLine("Sent frame " + i + " times\n");
i++;
}
Console.ReadKey();
}
}
Rx code
class Program
{
static IPEndPoint RxEndpoint = new IPEndPoint(IPAddress.Any, 8051); // IP from where I can receive the frame
static UdpState state1 = new UdpState();
static UdpClient Rx;
static int i = 0;
static void Main(string[] args)
{
Rx = new UdpClient(RxEndpoint);
state1.Rxclient = Rx;
state1.Endpoint = RxEndpoint;
Rx.BeginReceive(new AsyncCallback(RecieveCallback1), state1);
while (true)
{ }
}
public static void RecieveCallback1(IAsyncResult ar)
{
UdpClient Rx1 = (UdpClient)((UdpState)(ar.AsyncState)).Rxclient;
IPEndPoint End1 = (IPEndPoint)((UdpState)(ar.AsyncState)).Endpoint;
Byte[] receiveBytes = Rx1.EndReceive(ar, ref End1);
Console.WriteLine("Recieved " + (i++) + "Frame and its data is -> " + receiveBytes + "\n");
Rx.BeginReceive(new AsyncCallback(RecieveCallback1), state1);
}
}
class UdpState
{
public UdpClient Rxclient;
public IPEndPoint Endpoint;
}
There's only one reason you would actually want to use an external network to exchange data between two processes in the same machine, and that's if you want to detect whether the link between them (and intervening switches) is up.
For that you should use IEEE 802.1d Spanning Tree Protocol. If and only if both ports converge to membership in the same tree, there's a link between them.
If the two programs are running on the same host device and you want to communicate between them, you should use the loopback interface instead of sending out one physical interface and receiving on another.
The loopback interface is more efficient because it is all within software and is easier to use. Configure you sender to send to 127.0.0.1 and bind your receiver to 127.0.0.1. You can use the same ports in your example.
I want to preface this by saying my understanding of UDP Broadcasting and Multicasting is very limited. This is my first project working on this.
I have a C# desktop client running on a machine and a Windows phone 7 app.
The WP7 app is supposed to send a UDP broadcast over the network and the desktop client is supposed to listen for a UDP Multicast and respond accordingly. This is just meant for simple machine discovery over the network to find machines running the desktop client.
C# Desktop Client Code
public class ConnectionListener
{
private const int UDP_PORT = 54322;
private static readonly IPAddress MULTICAST_GROUP_ADDRESS = IPAddress.Parse("224.0.0.1");
private UdpClient _listener;
public ConnectionListener()
{
_listener = new UdpClient(UDP_PORT, AddressFamily.InterNetwork);
_listener.EnableBroadcast = true;
_listener.JoinMulticastGroup(MULTICAST_GROUP_ADDRESS);
_listener.BeginReceive(ReceiveCallback, null);
}
private void ReceiveCallback(IAsyncResult result)
{
IPEndPoint receiveEndpoint = new IPEndPoint(IPAddress.Any, UDP_PORT);
byte[] receivedBytes = _listener.EndReceive(result, ref receiveEndpoint);
byte[] response = Encoding.UTF8.GetBytes("WPF Response");
_listener.BeginSend(response, response.Length, receiveEndpoint, SendCallback, null);
}
private void SendCallback(IAsyncResult result)
{
int sendCount = _listener.EndSend(result);
Console.WriteLine("Sent Count is: " + sendCount);
}
}
The WP7 Server code:
public class MachineDetector
{
public const int UDP_PORT = 54322;
private const string MULTICAST_GROUP_ADDRESS = "224.0.0.1";
UdpAnySourceMulticastClient _client = null;
bool _joined = false;
private byte[] _receiveBuffer;
private const int MAX_MESSAGE_SIZE = 512;
public MachineDetector()
{
_client = new UdpAnySourceMulticastClient(IPAddress.Parse(MULTICAST_GROUP_ADDRESS), UDP_PORT);
_receiveBuffer = new byte[MAX_MESSAGE_SIZE];
_client.BeginJoinGroup(
result =>
{
_client.EndJoinGroup(result);
_client.MulticastLoopback = false;
SendRequest();
}, null);
}
private void SendRequest()
{
byte[] requestData = Encoding.UTF8.GetBytes("WP7 Multicast");
_client.BeginSendToGroup(requestData, 0, requestData.Length,
result =>
{
_client.EndSendToGroup(result);
Receive();
}, null);
}
private void Receive()
{
Array.Clear(_receiveBuffer, 0, _receiveBuffer.Length);
_client.BeginReceiveFromGroup(_receiveBuffer, 0, _receiveBuffer.Length,
result =>
{
IPEndPoint source;
_client.EndReceiveFromGroup(result, out source);
string dataReceived = Encoding.UTF8.GetString(_receiveBuffer, 0, _receiveBuffer.Length);
string message = String.Format("[{0}]: {1}", source.Address.ToString(), dataReceived);
Console.WriteLine(message);
Receive();
}, null);
}
}
I am able to receive data with the desktop client, but the WP7 app doesn't seem able to receive the response. I've been banging my head on this for a while now and don't know where else to look. Any help would be great.
So, any suggestions why the WP7 app isn't receiving a response?
I think the issue is with ConnectionListener:ReceiveCallback in C# Desktop Client.
_listener.BeginSend(response, response.Length,
receiveEndpoint, SendCallback, null);
Instead call
_listener.BeginSend(response, response.Length,
SendCallback, null);
This will cause the message to be sent to the multicast address. For further help with this refer to How to: Send and Receive Data in a Multicast Group for Windows Phone.
WP7 needs to multicast to the network in order to efficiently reach all desktop clients in one sweep. For the client response, the only intended destination is WP7. As such, a multicast has no real advantage here (as the desktop clients tuned into the multicast will effectively be ignoring it).
Instead, you could use receiveEndpoint populated by the call to EndReceive in ConnectionListener:ReceiveCallback to send a unicast response to the WP7 server. This is recommended consideration for creating multicast applications at MSDN.
This way WP7 no longer needs to join the multicast group for incoming multicast and the desktop client needn't send a multicast to respond.
I'm having a bit of trouble in getting a very simple TCP client working on my HTC Titan w/ Windows Phone 7.5.
When the USB cable is attached to the phone, the TCP client works like a charm, but as soon as the cable is unplugged, the client is unable to connect to a TCP server running on my development machine. The devices are on the same network and I'm using the explicit IP-address of my desktop machine to connect, so there's no name resolution going on afaik.
Here's the code I use. Most of it was taken from the Sockets samples on MSDN (can't seem to find the link now though).
private Socket _sock = null;
private ManualResetEvent _done = new ManualResetEvent(false);
private const int TIMEOUT = 5000;
//connect to server
public string Connect(string ip, int port) {
string result = string.Empty;
var host = new IPEndpoint(IPAddress.Parse(ip), port);
_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_sock.SetNetworkRequirement(NetworkSelectionCharacteristics.NonCellular);
var args = new SocketAsyncEventArgs();
args.RemoteEndPoint = host;
args.Completed += new EventHandler((s,e) => {
result = e.SocketError.ToString();
_done.Set();
});
_done.Reset();
_sock.ConnectAsync(args);
_done.WaitOne(TIMEOUT);
return result;
}
//send message
public string Send(string msg) {
string response = "Operation timeout";
if (_sock != null) {
var args= new SocketAsyncEventArgs();
args.RemoteEndPoint = _sock.RemoteEndPoint;
args.Completed += new EventHandler(s, e) => {
response = e.SocketError.ToString();
_done.Set();
});
var payload = Encoding.UTF8.GetBytes(data);
args.SetBuffer(payload, 0, payload.Length);
_done.Reset();
_sock.SendAsync(args);
_done.WaitOne(TIMEOUT);
}
return response;
}
//receive message
public string Receive() {
string response = "Operation timeout";
if (_sock != null) {
var args= new SocketAsyncEventArgs();
args.RemoteEndPoint = _sock.RemoteEndPoint;
args.SetBuffer(new Byte[MAX_BUFSIZE], 0, MAX_BUFSIZE);
args.Completed += new EventHandler((s,e) => {
if (e.SocketError == SocketError.Success) {
response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
response = response.Trim('\0');
}
else {
response = e.SocketError.ToString();
}
_done.Set();
});
_done.Reset();
_sock.ReceiveAsync(args);
_done.WaitOne(TIMEOUT);
}
return response;
}
The code is then simply used like:
Connect(...);
Send(...);
Receive(...);
//and then close the socket
As I said before, the code works like a charm when the device is attached to my development machine. When the cable is unplugged, the connection phase just times out (regardless of the timeout interval I should say).
Also, the manifest contains the ID_CAP_NETWORKING capability which as I understand it should give the app permission to access the network.
Any ideas?
EDIT:
I discovered that switching to UDP communication works like a charm. Which means that the problem is that for some reason, the phone is unable to set up a persistant TCP connection to my dev machine. This is getting stranger by the minute.
Do you have a wireless ap nearby on which your phone is connected? because when you plug it in the pc it uses the pc's network connection.
You should check the IP address that you have on both the phone (from your code) and on the PC (which it looks like you've already found using ipconfig in your command prompt).
These should be in the same IP address range, and so start with the same digits (for IPv4, probably something link 192.168.0.*).
If this all matches up check your wireless router hasn't enabled a security setting which means that it doesn't allow TCP traffic from your phone to your PC.
If this is a consumer router you manage this should be fairly simple to verify (and potentially fix). If not, you're probably stuck...