C# - Can't receive UDP on second computer - c#

I can send UDP messages from one computer to itself on a certain port but I can't send this messages from one computer to another in the same lan. I am pretty new to C# and I am also new to network programming so the solution is probably easy...
I have tried an example from Microsoft Docs and did only small changes. (names, etc.)
Both codes run as seperate programs.
//RECEIVE
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class UDPListener
{
private const int listenPort = 11000;
private static void Listen()
{
UdpClient listener = new UdpClient(listenPort);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, listenPort);
try
{
while (true)
{
Console.WriteLine("Waiting for broadcast");
byte[] receivebytes = listener.Receive(ref groupEP);
Console.WriteLine(Encoding.ASCII.GetString(receivebytes, 0, receivebytes.Length));
}
}
catch (SocketException e)
{
Console.WriteLine(e);
}
finally
{
listener.Close();
}
}
public static void Main()
{
Listen();
}
}
//SEND
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class Program
{
static void Main(string[] args)
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//192.168.2.5 is the IP Address of the receiving computer
IPAddress broadcast = IPAddress.Parse("192.168.2.5");
byte[] bytestosend = Encoding.ASCII.GetBytes("Hi");
IPEndPoint ep = new IPEndPoint(broadcast, 11000);
socket.SendTo(bytestosend, ep);
Console.WriteLine("bytestosend were send");
}
}
The sending program tells me that the message was sent but the receiving program gives no output.
EDIT 1: The Ressource Manager said that on the receiving computer was no network activity while on the sending computer is actually sending something.
EDIT 2: I tried my applications in an other network and it worked fine. I did some research and I found that sometimes routers don't allow udp broadcasts through a subnet (or anything similar...). So I assume it might be my router. (unfortunately I can not access it's settings.) So I think the problem has resolved itself!

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

Why do I need two sockets in server application?

I am trying to learn socket programming in C#
By using google I found a lot of good tutorials and examples.
But here is my own code :
Sender application :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net; // socket library
using System.Net.Sockets; // socket library
namespace Sender
{
class Program
{
static void Main(string[] args)
{
Console.Write("Enter remote IP : ");
IPAddress ipAddress = IPAddress.Parse(Console.ReadLine());
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sender.Connect(ipAddress, 4444);
Console.Write("Enter text to send : ");
byte[] message = Encoding.ASCII.GetBytes(Console.ReadLine().ToString());
sender.Send(message);
sender.Shutdown(SocketShutdown.Both);
sender.Close();
Console.ReadKey();
} // main
} // main
} // main
Receiver application :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net; // socket library
using System.Net.Sockets; // socket library
namespace Listener
{
class Program
{
static void Main(string[] args)
{
IPAddress ipAddress = Dns.GetHostAddresses(Dns.GetHostName()).Where(address => address.AddressFamily == AddressFamily.InterNetwork).First();
Console.WriteLine("Listening on " + ipAddress.ToString() + " : 4444");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 4444);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEndPoint);
listener.Listen(10);
Socket handler = listener.Accept();
byte[] bytes = new Byte[1024];
int bytesRec = handler.Receive(bytes);
Console.WriteLine(Encoding.ASCII.GetString(bytes, 0, bytesRec));
handler.Shutdown(SocketShutdown.Both);
handler.Close();
listener.Close();
Console.ReadKey();
} // main
} // main
} // main
The code works fine, but I want to know why do I need two sockets in server side? The first one is listener and the second one is handler. Is it possible to omit one of them so that the code become more simple?
By the way my code is based on these codes :
Synchronous Client Socket Example : https://learn.microsoft.com/en-us/dotnet/framework/network-programming/synchronous-client-socket-example
Synchronous Server Socket Example : https://learn.microsoft.com/en-us/dotnet/framework/network-programming/synchronous-server-socket-example
Also I am using Microsoft Visual C# 2008 Express Edition
The listener socket is listening for the incoming connections. If there were no handler socket, then there were no one to listen for parallel incoming connections until the communication with the client is over.
That's why Accept returns another socket, which is used for communication, and the listening socket continues waiting for incoming connections.
You can see it as a kind of weakly-typed objects: the Socket is responsible for both listening and communication roles, although it might be better to have different types for these two different tasks. But this behaviour reflects the traditional socket behaviour, so it remains as it is in order to be familiar to the people having background in network programming.
The more high-level API (TcpListener and TcpClient) makes a clear distinction between listening and communication roles.

Open TCP port using UDP?

I read something about using UDP to open ports. I can't find the original page I read but I did find this SO answer https://stackoverflow.com/a/1539394
I tried running this code. Perhaps I did something wrong? The idea (in link above) was Alice listens to port 5412, sends a UDP packet to bob from 5412 (the tcp port) to 5411. Bob (who doesn't listen) uses TCP port 5411 (the udp port) to connect to Alice 5412. I use the command line on bob to give alice IP address.
Did I do this wrong? When I run locally using my public IP address (and my network address but not 127.0.0.1) I get the exception A socket operation was attempted to an unreachable network. When I run it on Bob I get a connection timeout exception.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace TcpTest
{
class Program
{
static string localIp = "127.0.0.1";
static string remoteIP = ipaddr;
static void Main(string[] args)
{
//run remotely to connect to you using TCP
if (args.Count() > 0)
{
var t = new TcpClient(new IPEndPoint(IPAddress.Parse(localIp), 5411)); //Force port
t.Connect(args[0], 5412);
return;
}
//Run locally
//Bind TCP port
var l = new TcpListener(5412);
l.Start();
//Send UDP using the listening port to remote address/port
var u = new UdpClient(5412);
u.Connect(remoteIP, 5411);
var buf = new byte[10];
u.Send(buf, buf.Length);
//R
new Thread(SimulateRemote).Start();
//L
var c = l.AcceptTcpClient();
var af=c.Client.RemoteEndPoint;
}
static void SimulateRemote()
{
Thread.Sleep(500);
var t = new TcpClient(new IPEndPoint(IPAddress.Parse(localIp), 5411)); //Force port
t.Connect(myipaddr, 5412);
}
}
}
You can't do that.
TCP ports and UDP ports can't connect to each other. The packets you send from UdpClient.Send() have the Protocol field set to 0x11, the value for UDP, but the TCP stack only recognizes packets with Protocol set to 0x06, the value for TCP. It's part of the most-basic operation of an IP module. See RFC 791 if you want the details.

When to close a UDP socket

I have a client-server application that uses a UDP socket to send the data , the data only have to travel from client to server , and the server will always have the same IP. The only requirement is that I have to send messages about 10 messages per second
Currently I am doing it the following way :
public void SendData(byte[] packet)
{
IPEndPoint end_point = new IPEndPoint(serverIP, serverPort);
UdpClient udpChannel = new UdpClient(sourcePort);
udpChannel.Connect(end_point);
udpChannel.Send(packet, packet.Length);
udpChannel.Close();
}
The problem I have is that when I use the command "udpChannel.Close()" it takes 2-3 seconds to be performed when the server is not listening. (I've seen the same problem in: What is the drawback if I do not invoke the UdpClient.Close() method?)
My question would be, if I always send packets to the same IP address and port, is it necessary to connect the socket and close it after each send request?
The code I intend to use would be as follows:
UdpClient udpChannel;
public void SendData(byte[] packet)
{
udpChannel.Send(packet, packet.Length);
}
public void Initialize(IPAddress IP, int port)
{
IPEndPoint end_point = new IPEndPoint(serverIP, serverPort);
UdpClient udpChannel = new UdpClient(sourcePort);
udpChannel.Connect(end_point);
}
public void Exit()
{
udpChannel.Close();
}
Doing it this way, would it be necessary to do some checking in the "SendData" method before sending the data?
Is there any problem in the above code?
Thank you!
UDP is connectionless, calling udpChannel.Connect merely specifies a default host endpoint for use with the Send method. You do not need to close the client between sends, leaving it open will not leave any connections or listeners running between sends.
You shouldn't connect/close after each send request. When you start working - you connect to socket. And you can send data. You should close UdpClient when you do not want to send/recieve data, for example when you closing Form.
In your case you can check that udpClient != null when close/send client and you can use try/catch, for example:
try
{
udpClient.Send(sendBytes, sendBytes.Length);
}
catch (Exception exc)
{
// handle the error
}
Use try/catch when you connecting, because port may be busy or other problem with connection.
And look at UdpClient.SendAsync :)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using System.Text;
using System.Net.Sockets;
using System;
using System.Net;
public class Server : MonoBehaviour
{
//int[] ports;
UdpClient udp; // Udp client
private void Start()
{
udp = new UdpClient(1234);
udp.BeginReceive(Receive, null);
}
void Send(string msg, IPEndPoint ipe)
{
UdpClient sC = new UdpClient(0);
byte[] m = Encoding.Unicode.GetBytes(msg);
sC.Send(m, msg.Length * sizeof(char), ipe);
Debug.Log("Sending: " + msg);
sC.Close();
}
void Receive(IAsyncResult ar)
{
IPEndPoint ipe = new IPEndPoint(IPAddress.Any, 0);
byte[] data = udp.EndReceive(ar, ref ipe);
string msg = Encoding.Unicode.GetString(data);
Debug.Log("Receiving: " + msg);
udp.BeginReceive(Receive, null);
}
}
At the Send() I use new UDP CLient and close it after every time. Its better, u can send and receive at the same time.

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