Receiving UDP packets in Unity Android application with broadcast - c#

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();
}

Related

Listen to message from an IP from another machine

I am trying to send a message to Unity through UDP. The machine that sends the message has IP as 192.16.14.1 and port as 3034. How do I enter these two inside of Unity application? I have found a code to listen for UDP messages but I cannot set the IP address here. Also the Unity application should be running at all times even if the message from another machine is sent or not.
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using UnityEngine;
public class UDP_Listen : MonoBehaviour
{
UdpClient clientData;
int portData = 3034;
public int receiveBufferSize = 120000;
public bool showDebug = false;
IPEndPoint ipEndPointData;
private object obj = null;
private System.AsyncCallback AC;
byte[] receivedBytes;
void Start()
{
InitializeUDPListener();
}
public void InitializeUDPListener()
{
ipEndPointData = new IPEndPoint(IPAddress.Any, portData);
clientData = new UdpClient();
clientData.Client.ReceiveBufferSize = receiveBufferSize;
clientData.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, optionValue: true);
clientData.ExclusiveAddressUse = false;
clientData.EnableBroadcast = true;
clientData.Client.Bind(ipEndPointData);
clientData.DontFragment = true;
if (showDebug) Debug.Log("BufSize: " + clientData.Client.ReceiveBufferSize);
AC = new System.AsyncCallback(ReceivedUDPPacket);
clientData.BeginReceive(AC, obj);
Debug.Log("UDP - Start Receiving..");
}
void ReceivedUDPPacket(System.IAsyncResult result)
{
//stopwatch.Start();
receivedBytes = clientData.EndReceive(result, ref ipEndPointData);
ParsePacket();
clientData.BeginReceive(AC, obj);
//stopwatch.Stop();
//Debug.Log(stopwatch.ElapsedTicks);
//stopwatch.Reset();
} // ReceiveCallBack
void ParsePacket()
{
// work with receivedBytes
Debug.Log("receivedBytes len = " + receivedBytes.Length);
}
void OnDestroy()
{
if (clientData != null)
{
clientData.Close();
}
}
}
If the Unity application is to be receiving the messages constantly, it needs to be something like:
UdpClient listener = new UdpClient(11000);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Parse("192.16.14.1"), 3034);
while (true)
{
byte[] bytes = listener.Receive(ref groupEP);
}
This should read only calls from the specific IP, not sure which port you want the UDPClient to read out from (specified in the UDPClient constructor) but you can set this to whatever you need it to be.
So there are two different things:
You want to define the receiving local port you Bind your socket to
You want to define the expected sending remote ip + port you want to Receive from
Currently you are using the very same one
ipEndPointData = new IPEndPoint(IPAddress.Any, portData);
for both! (Fun fact: As a side effect by using always the same field you basically allow any sender but are then bond to that specific sender from this moment on)
Actually a lot of things you configure there are the default values anyway so here is more or less what I would do
using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;
public class UDP_Listen : MonoBehaviour
{
public ushort localReceiverPort = 3034;
public string senderIP = "192.168.111.1";
public ushort remoteSenderPort = 3034;
public bool showDebug = false;
// Thread-safe Queue to handle enqueued actions in the Unity main thread
private readonly ConcurrentQueue<Action> mainThreadActions = new ConcurrentQueue<Action>();
private Thread udpListenerThread;
private void Start()
{
// do your things completely asynchronous in a background thread
udpListenerThread = new Thread(UDPListenerThread);
udpListenerThread.Start();
}
private void Update()
{
// in the Unity main thread work off the actions
while (mainThreadActions.TryDequeue(out var action))
{
action?.Invoke();
}
}
private void UDPListenerThread()
{
UdpClient udpClient = null;
try
{
// local end point listens on any local IP
var localEndpoint = new IPEndPoint(IPAddress.Any, localReceiverPort);
udpClient = new UdpClient(localEndpoint);
if (showDebug)
{
Debug.Log("BufSize: " + clientData.Client.ReceiveBufferSize);
}
Debug.Log("UDP - Start Receiving..");
// endless loop -> ok since in a thread and containing blocking call(s)
while (true)
{
// remote sender endpoint -> listens only to specific IP
var expectedSenderEndpoint = new IPEndPoint(IPAddress.Parse(senderIP), remoteSenderPort);
// blocking call - but doesn't matter since this is a thread
var receivedBytes = udpClient.Receive(ref expectedSenderEndpoint);
// parse the bytes here
// do any expensive work while still on a background thread
mainThreadActions.Enqueue(() =>
{
// Put anything in here that is required to happen in the Unity main thread
// so basically anything using GameObject, Transform, etc
});
}
}
// thrown for "Abort"
catch (ThreadAbortException)
{
Debug.Log("UDP Listener terminated");
}
// Catch but Log any other exception
catch (Exception e)
{
Debug.LogException(e);
}
// This is run even if an exception happend
finally
{
// either way dispose the UDP client
udpClient?.Dispose();
}
}
private void OnDestroy()
{
udpListenerThread?.Abort();
}
}
I'm sure the same can be done also using the BeginReceive/EndReceive or task based alternatives but since it is going to run endless anyway I personally find a thread often easier to read and maintain.
I think you got it backwards. This code you shared is for, like you said, listen UDP protocol on desired port. This piece of code needs to be inside your "server". By server try to understand that as the receiving side.
on your shared method InitializeUDPListener(); we have this piece:
ipEndPointData = new IPEndPoint(IPAddress.Any, portData);
this means you are initializing your udp socket to listen for ANY ip adresses at the given port. That said, you have your server ready to go, what you need to do is setup the client side, the one who sends the message.
here some example:
public string serverIp = "127.0.0.1"; // your server ip, this one is sending to local host
public int serverPort = 28500; // your server port
public void ClientSendMessage()
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPAddress broadcast = IPAddress.Parse(serverIp);
byte[] sendbuf = Encoding.ASCII.GetBytes("THIS IS A MESSAGE FROM CLIENT!");
IPEndPoint ep = new IPEndPoint(broadcast, serverPort);
s.SendTo(sendbuf, ep);
}
I encourage you to read about UDP/TCP protocols before using them. MS has documentation with details.
here some links:
TCP
UDP
Sockets

How to Make Simple C# Windows Form Application UDP Socket Tester

Hello everyone I am very new to Visual Studio, C# programming, and Windows Form Applications.
My need is very simple - I want to create my own small program to listen to data being sent by a GPS device over UDP. I do not need to communicate, just listen and see the data on the screen!
Something that works exactly the same as this :
http://sockettest.sourceforge.net/ (see 'UDP' tab)
My GPS device has an IP of 192.168.1.1 and sends a sting of numbers every 1 second, continuously, transmitting on UDP 25.255.255.255:5017.
All the examples on the internet seems to focus on 2-way communicate, client and server chat windows etc. There is a lot of confusing terminology like synchronous and a-synchronous, client, server, UDP, TCP, binding.
I just want an even more simplified program than the above example, where I can type in the port number 5017, click Start Listening, and then straight away works!
All advice and code examples very gratefully received!!
Many thanks,
Jon
I now have it working, and can receive data in a textbox in the UI!
I use button_start_Click to open the port and start receiving. However, I cannot get button_stop_Click to work. How can you stop/close/disconnect/endReceive using button click?
public Form1()
{
InitializeComponent();
}
private void button_start_Click(object sender, EventArgs e)
{
Client = new UdpClient(Convert.ToInt32(textBox_port.Text));
Client.BeginReceive(DataReceived, null);
}
private void DataReceived(IAsyncResult ar)
{
IPEndPoint ip = new IPEndPoint(IPAddress.Any, Convert.ToInt32(textBox_port.Text));
byte[] data;
try
{
data = Client.EndReceive(ar, ref ip);
if (data.Length == 0)
return; // No more to receive
Client.BeginReceive(DataReceived, null);
}
catch (ObjectDisposedException)
{
return; // Connection closed
}
// Send the data to the UI thread
this.BeginInvoke((Action<IPEndPoint, string>)DataReceivedUI, ip, Encoding.UTF8.GetString(data));
}
private void DataReceivedUI(IPEndPoint endPoint, string data)
{
txtLog.AppendText("[" + endPoint.ToString() + "] " + data + Environment.NewLine);
}
private void button_stop_Click(IAsyncResult ar) // NOT WORKING!! AGH!
{
IPEndPoint ip = new IPEndPoint(IPAddress.Any, Convert.ToInt32(textBox_port.Text));
byte[] data;
data = Client.EndReceive(ar, ref ip);
Client.Close();
}
Run the same code in background worker and then you can cancel the background worker anytime using backgroundworker.cancelasync().
Hope this helps.

How to receive UDP packages when using UdpClient class in C#

I am trying to write a graphical C# program that can communicate with my Node.js server.
I am using UdpClient class and I am able to send some messages to the server.
However, I don't know how to receive UDP packages from the server.
JavaScript and Windows Form Widgets are event-driven, but UdpClient class in C# doesn't have any convenient events related to data reception.
Also, I don't know where to put the code of package reception. Most of online examples are console program and my program is GUI based.
I want my program to continuously listen at a port and when a package comes in, the program can capture the package and display its content in a TextBox.
Any suggestions ?
You can listen to a port asynchronously using BeginReceive. It works in GUI applications too - just remember to send the data to the UI thread before interacting with the UI.
This example is from a WinForms application. I've put a multiline textbox on the form called txtLog.
private const int MyPort = 1337;
private UdpClient Client;
public Form1() {
InitializeComponent();
// Create the UdpClient and start listening.
Client = new UdpClient(MyPort);
Client.BeginReceive(DataReceived, null);
}
private void DataReceived(IAsyncResult ar) {
IPEndPoint ip = new IPEndPoint(IPAddress.Any, MyPort);
byte[] data;
try {
data = Client.EndReceive(ar, ref ip);
if (data.Length == 0)
return; // No more to receive
Client.BeginReceive(DataReceived, null);
} catch (ObjectDisposedException) {
return; // Connection closed
}
// Send the data to the UI thread
this.BeginInvoke((Action<IPEndPoint, string>)DataReceivedUI, ip, Encoding.UTF8.GetString(data));
}
private void DataReceivedUI(IPEndPoint endPoint, string data) {
txtLog.AppendText("[" + endPoint.ToString() + "] " + data + Environment.NewLine);
}

UDP in C# works on Windows but not Linux

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());
}
}
}

Testing of socket communication program

Am starting with socket programming with a simple UDPClient program to send some data. The large code snippet is below:
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
class ShowIP
{
public static void Main(string[] args)
{
string name = Dns.GetHostName();
//name = "GSL1460";
name = "GSL1296";
try
{
IPAddress[] addrs = Dns.GetHostEntry(name).AddressList;
foreach (IPAddress addr in addrs)
Console.WriteLine("{0}/{1}", name, addr);
Console.WriteLine("Started listening");
Thread listenerThread = new Thread(new ThreadStart(StartListeningUDP));
listenerThread.Start();
Console.WriteLine("Started sending");
for (int counter = 0; counter <= 3; counter++)
{
Thread.Sleep(1000);
Console.WriteLine("Sending {0} time", counter.ToString());
StartSendingUDP(addrs[0]);
}
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
private static void StartListeningUDP()
{
UdpClient udpListener = null;
IPEndPoint nwPoint = new IPEndPoint(IPAddress.Any, 12345);
while (true)
{
try
{
udpListener = new UdpClient(12345);
Console.WriteLine("Waiting to receive");
Byte[] receivedBytes = udpListener.Receive(ref nwPoint);
string receivedData = Encoding.ASCII.GetString(receivedBytes);
Console.WriteLine("Data received : " + receivedData);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
udpListener.Close();
}
}
}
private static void StartSendingUDP(IPAddress clientAddress)
{
UdpClient udpSender = new UdpClient();
try
{
Byte[] sendBytes = Encoding.ASCII.GetBytes("Say HI to Papa...");
Console.WriteLine("Data Sent : Say HI to Papa...");
udpSender.Send(sendBytes, sendBytes.Length, new IPEndPoint(clientAddress, 12345));
}
finally
{
udpSender.Close();
}
}
}
The sample works fine on local machine, but am not able to send data to another machine on the intranet.
During testing
Am uncommenting the appropriate code to send data to his machine
Am running the Receiver bit on his machine
Have checked that the required port is open on his machine
Am I missing something? Please suggest.
udpSender.Flush?
I'm not a C# person, so I can't comment too much on your code, but it looks basically okay. Make sure that the IP address you're sending to is being resolved correctly to your receiving machine.
Also, see if Windows has firewalled your internet connection, and try disabling the firewall if so. And, I know that Microsoft has some ideas about "safe" code that have caused us some problems in the past. I don't have any specifics, but there might be settings in the project that keep it from being able to access the network.
The UDP-Listener might be listening on localhost only. You could try to replace
udpListener = new UdpClient(12345)
in StartListeningUDP() with
udpListener = new UdpClient(new IPEndPoint(IPAddress.Any,12345))
you can't really send UDP over the internet without doing few things before.
you will get too many udp filters on the way.
even if you will disable your firewall, your router/provider modem can be set to block it.
else - your provider servers will block it.
so in fact you will have to make sure that this port is open for UDP, just as on your localhost it won't work unless you will open this port in the firewall and/or install the loopback adapter

Categories