C# How to send string via UDP without Port Forwarding? - c#

I need something simillar to this:
var client = new UdpClient();
IPEndPoint ep = new IPEndPoint(IPAddress.Parse("23.114.44.195"), 11000);
client.Connect(ep);
byte[] data = Encoding.ASCII.GetBytes("test");
client.Send(data, data.Length);
The listener runs on that IP at PORT: 11000, but i don't want to port forward in my router (because I want to publish this app).
So, here is the question: How to send string via UDP without Port Forwarding?

You can use NAT hole punching, which doesn't require manual port forwarding configuration. It's quite simple technique. Please note that remote endpoint (receiver) should implement it too, not just sender.
In the simplest case, it works as:
[sender] <-> |internet| <-> [remote router with NAT] <-> [receiver]
Please note sender is not behind NAT.
To punch a hole from senderIP:portX to receiverIP:portY:
sender binds to portX and waits for communication initialisation from receiver. receiver binds to portY and sends a dummy packet to senderIP:portX. sender gets receiverIP (which is actually its router IP) and portY from the package and now sends meaningful data to this address. NAT remembered that communication with senderIP:portX was going from receivers local IP and portY, so all data coming from senderIP:portX to the router's portY will be redirected to receivers local IP.
For the case when both sender and receiver are behind NATs, you need a rendezvous server, for details check the link.

Related

C# UdpClient Can't Send Multicast UDP Packet

I have a laptop which has a wireless adapter with ip address "192.168.5.60". This laptop will send UDP Multicast packets.
I have a desktop pc which has a network adapter ip ""192.168.5.90". I installed a software named "Multicast Tester" which joins multicast group("239.194.190.22:4000") on this desktop pc.
Problem is if i use another software which i installed from internet on laptop and send multicast udp packets to "239.194.190.22:4000" i can receive these packets in desktop pc.
If I use my program to send these packets, i can't receive multicast packets.
My code :
UdpClient udpClient = new UdpClient();
udpClient.client.bind(new IPEndPoint(IPAddress.Parse("192.168.5.60"), 0));
udpClient.JoinMulticastGroup(IPAddress.Parse("239.194.190.22"));
udpClient.send(myData, myData.length, new IPEndPoint(IPAddress.Parse("239.194.190.22"), 4000));
Note : Both computers have multiple nics.
From your description, the problem is that your sender is sending out its system default multicast interface which happens to be an interface not on the link with the 192.168.5/24 network. If you use IP_MULTICAST_IF with either the sender's ip or the index of the interface (as shown by ipconfig) instead of IP_MULTICAST_TTL then the TTL of 1 is fine since you are then using the shared link, i.e:
_udpClient.Client.SetSocketOption(SocketOptionLevel.IP,
SocketOptionName.MulticastInterface, IPAddress.Parse("192.168.5.60").GetAddressBytes());
(Where you may need to do some more work on the address to make it a DWORD in network order, and based on ip options and enums)
I just solved it. It looks like default TTL value for UDP Multicast packets is '1'. !
I changed it to '16' by using this code:
_udpClient.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MuticastTimeToLive, 16);

Socket communication on a LAN environment

I have the following setup:
The server will connect via Bluetooth to several devices that are sending a discrete signal. Then there will be n clients that can inquiry the server (via web services probably) for which devices are connected and listen to the signal from the devices they want.
I think the best way to implement this is: when the server connects to a device via BT, it will open a Socket to a local port and send the data there. When a client ask for the available devices, the server will return a Dictionary and then the client just have to listen to that port.
But i'm having some problems with the socket implementation. How can I create and write the signal to a local port?
This is what I got so far:
class Device {
...
public EndPoint Connect() {
// create a bt connection to the device
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var endPoint = new IPEndPoint(IPAddress.Parse(_localIp), 0);
_socket.Bind(endPoint);
return endPoint;
}
private void OnBtDataReceived(object sender, wclDataEventArgs e) {
_socket.Send(e.Data);
}
}
But when reaching the _socket.Send(e.Data); I receive the following exception:
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Is this the right approach but it needs to have someone connected to the socket to read the data?
You can use UDP Broadcast as the comments suggest where you don't have to establish a connection. The server justs sends the data out on one port and any interested client can receive that data on that port.
If you want to distinguish between your devices you might have to broadcast every devices data on a separate port. That might be a lot of (unnecessary) network traffic whn you have many devices.
The other option is using TCP.
Your server as to listen for incoming connections from your clients:
_socket.Bind(new IPEndPoint(IPAddress.Any, 1234));
_socket.Listen(10);
_socket.BeginAccept(onAccept, _socket);
In onAccept you have access to the clientsocket and can send data or store the reference to the socket somewhere to send data later on:
private static void onAccept(IAsyncResult ar)
{
Socket clientSocket = ((Socket) ar.AsyncState).EndAccept(ar);
// begin to accept the next client connection
_socket.BeginAccept(onAccept, _socket);
// this is the socket you can send data to the connected client:
clientSocket.Send(data);
}
The TCP approach has the advantage that your server only sends data when there are connected clients and your server is aware of the number of clients connected.
When using TCP, you don't need to call Bind(), but you need to call Connect().
_socket.Connect(endPoint);
This assumes that in your code _localIp is an IP address on the local network you want to connect to and not an IP address of a network adapter on the local computer that you want to use for the connection.
What Bind() does is to bind the socket to a local (i.e. on the current computer) end point. If you don't care what network adapter is used (which means you let the system decide that based on the target IP), and you also don't care what local port is used, there is no need to call Bind().

C# Sockets, How to get IP addresses and port # of all listening (sockets) computers

I am using C# sockets to have a connection between a device (client) and a computer (server).
All is working good except for the fact that I am trying to avoid the user to enter the IP address and port number wherein to connect to on the device. Instead I want a listbox or drop down list of all IP addresses with listening sockets. Just wondering if there's a way to get all the IP addresses and port numbers of hosts with listening (socket)?
Thanks for any help! :)
What you're asking to do is called a port scan. It basically involves testing each IP address in a range and each port and reporting the success of that attempt. It's slow and it will cause a lot of alarms if there is any kind of threat monitoring on the network because port scanning is one of the ways attackers try to find network vulnerabilities.
So in short, this is a bad idea and probably won't be responsive enough for you to use for this purpose. Instead what you might consider is using a central server as a "directory" that each server would register with.
Or you can send out a broadcast on your subnet and wait for servers to respond. This is how some of the peer networking works in Windows for example. Note that this assumes you are the developer of the server as well and you can add in the logic necessary for the server to listen for broadcasts.
By using UDP broadcast, you can send out the data to the Server which are listening at the fixed port. The following is the working example.
foreach (IPAddress ip in allLocalNetworkAddresses.AddressList)
{
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//Allow sending broadcast messages
client.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.Broadcast, 1);
//Create endpoint, broadcast.
IPEndPoint AllEndPoint = new IPEndPoint(IPAddress.Broadcast, Port);
byte[] sendData = Encoding.ASCII.GetBytes("1");
//Send message to everyone on this network
client.SendTo(sendData, AllEndPoint);
Console.Write("Client send '1' to " + AllEndPoint.ToString() +
Environment.NewLine);

Send broadcast message from all network adapters

I have an application that sends broadcast messages and listens for response packets. Below is the code snippet.
m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
m_socket.Bind(new IPEndPoint(IPAddress.Any, 2000));
m_socket.BeginSendTo(
buffer,
0,
buffer.Length,
SocketFlags.None,
new IPEndPoint(IPAddress.Broadcast, 2000),
Callback),
null
);
When I run the application the broadcast message was not being sent. On my machine I have three network adapters. One is my local network adapter and other two are VMWare network virtual adapters. When I run my application I can see (using wireshark network capture) that the broadcast message is being sent from one of the VMWare network adapters.
I would like to modify the code so that the broadcast message will be sent from all network adapters on the pc. What is the best way to do that?
You can use the following to get all your IP Addresses (and a lot more). So you can iterate through the list and bind (like Jon B said) to the specific IP you want when you send out your multicast.
foreach (var i in System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces())
foreach (var ua in i.GetIPProperties().UnicastAddresses)
Console.WriteLine(ua.Address);
When you call Bind(), you are setting the local IP end point. Instead of using IPAddress.Any, use the IP address of the NIC that you want to send from. You'll need to do this separately for each NIC.
Check this http://salaam.codeplex.com/
I and my friend developed a class library called Salaam. download the source code or use the binaries (.dll) to use it.
You can use IPAddress.Any when constructing the tcpListener. This will bind the tcp listener to all interfaces

Multicast feed: use localhost?

I am being sent an xml feed via multicast, but I don't know the multicast group address. Can I just use localhost instead?
Socket socket =
new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
IPEndPoint ip = new IPEndPoint(IPAddress.Any,8888);
socket.Bind(ip);
socket.SetSocketOption
(SocketOptionLevel.IP,
SocketOptionName.AddMembership,
new MulticastOption(IPAddress.Parse("127.0.0.1"),IPAddress.Any));
byte[] data = new byte[1024];
int length = socket.Receive(data);
...
No.
You (your client) needs to join the multicast group, you'll AddMembership to the multicast group IP, then connect.
Otherwise you won't be able to receive the multicast feed. Your code would work with a UDP broadcast though.
Strictly speaking, if you open a listening port for multicast data on a non-multicast address, then you are essentially listening to standard UDP. The difference between multicast and UDP is in the IP address. Its a special IPV4 address range that is not tied to a fixed host. Rather it is recognized by the routers on the edges of your network in a pseudo publish-subscribe fashion. Within your sub-net multicast is for all intents and purposes the same as broadcast.
If you write to a multicast address, it is available to all hosts on your subnet. If your router supports multicast, then it will provide it upstream to any clients that announce that they are interested in it. THink of it as publish/subscribe for subnets.
All of this to say, if you are looking for a localhost equivalent to multicast, then you probably need to look at broadcast instead.
Unlike unicast, you do need to know the group address for multicast.

Categories

Resources