I am making an Win RT app that connects to a desktop app and they start to communicate in UDP and TCP.
I have successfully implemented TCP communication in that I can send from Win RT to Desktop and send from Desktop to Win RT. using StreamSocket on Win RT and TcpListener on desktop.
I also made it to send Udp data from Win RT to desktop without any problem. But I can't receive data's sent from desktop to Win RT. I use the following code and I don't see any problem with that but there must something.
var g = new DatagramSocket();
g.MessageReceived += g_MessageReceived;
g.BindEndpointAsync(new HostName("127.0.0.1"), "6700");
.
.
.
void g_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
{ // <- break point here.
}
That break point never stops the code which means it never gets a message.
I can only think of IBuffer because on my StreamSocket I should get the bytes by reader.GetBuffers() and not reader.GetBytes(). However that's the thing I need to think about on the Win RT and not Desktop. because on Tcp I just send bytes and I get buffers in Win RT so the same should happen for DatagramSocket as well.
reader = DataReader
Thank you guys.
I'm not familiar with the new DatagramSocket class, but usually binding to 127.0.0.1 means that you will only receive messages sent to the loopback adapter. Since your packets are coming from another host, they should be received on a NIC, not the loopback adapter.
Edit: From looking at the documentation for the DatagramSocket API that you're using, you can just use the BindServiceNameAsync() method instead of BindEndpointAsync() in order to bind to the specified port on all adapters, which is the same behavior as my System.Net.Sockets API example below. So, in your example, you'd have:
g.BindServiceNameAsync("6700");
Of course, you'll also want to make sure your firewall settings on the desktop host allow it to listen for incoming UDP packets on the specified port.
Try the following code:
using System.Net;
using System.Net.Sockets;
public class UdpState
{
public UdpClient client;
public IPEndPoint ep;
}
...
private void btnStartListener_Click(object sender, EventArgs e)
{
UdpState state = new UdpState();
//This specifies that the UdpClient should listen on EVERY adapter
//on the specified port, not just on one adapter.
state.ep = new IPEndPoint(IPAddress.Any, 31337);
//This will call bind() using the above IP endpoint information.
state.client = new UdpClient(state.ep);
//This starts waiting for an incoming datagram and returns immediately.
state.client.BeginReceive(new AsyncCallback(bytesReceived), state);
}
private void bytesReceived(IAsyncResult async)
{
UdpState state = async.AsyncState as UdpState;
if (state != null)
{
IPEndPoint ep = state.ep;
string msg = ASCIIEncoding.ASCII.GetString(state.client.EndReceive(async, ref ep));
//either close the client or call BeginReceive to wait for next datagram here.
}
}
Note that in the above code, you should obviously use whatever encoding you're sending the string across with. When I wrote that test app, I sent the string in ASCII. If you're sending it in Unicode, just use UnicodeEncoding.Unicode instead of ASCIIEncoding.ASCII.
If none of this works, you might want to break out a packet capture utility like Wireshark to make sure that the UDP packet from the RT host is, in fact, getting to the desktop host.
Related
I'm trying directly connect (using TCP) two devices that are behind routers implementing NAT. As I see, routers are translating port number of my devices, so port 13000 (port where my app is listening for incoming TCP connections) on my computer will have completly different value as seen publicly. In order to connect two devices, I need to know what the listener's "public port number" is.
I've created "rendezvous server" which is available publicly. Firstly, I've created TCP connection between client A and server. Server extracted port number and passed it to other clients so they could try to connect to client A. But I realized, that when I create new Tcp connection with server, my app creates new port from which it sends packets. So server extracts public port of newly created port used just for connection to that server and not public port of my listener.
So I'm trying to solve it other way. The idea is: I'm sending UDP packets with source port set to port of TcpListener. This way, theoretically, server could extract from incoming message public port of TcpListener (by getting source port from UDP datagram) and pass it to other devices in my network.
// client side
public void AdvertiseListener(IPAddress address, int port, Guid localDeviceId)
{
UdpClient client = new UdpClient(ListenerPort); // changing datagram source to port of my TcpListener
IPEndPoint remoteEP = new IPEndPoint(address, port);
_logger.LogInformation($"Advertising Tcp port to server at {address.MapToIPv4().ToString()}:{port}");
byte[] data = localDeviceId.ToByteArray();
for (int a = 0; a < 10; a++)
{
client.Send(data, data.Length, remoteEP);
}
}
// server side
public void AdvertisementsHandler()
{
AdvertisementListener = new UdpClient(ListenerPort);
AdvertisementListener.BeginReceive(new AsyncCallback(HandleAdverticement), null);
}
private void HandleAdverticement(IAsyncResult ar)
{
IPEndPoint senderIpEndPoint = new IPEndPoint(0, 0); // source address of incoming datagram
var receivedData = AdvertisementListener.EndReceive(ar, ref senderIpEndPoint);
[...]
_logger.LogInformation($"ADVERTICEMENT RECEIVED, port is {senderIpEndPoint.Port}");
try
{
AdvertisementListener.BeginReceive(new AsyncCallback(HandleAdverticement), null);
}
catch (Exception e)
{
_logger.LogError("Advertiser failed");
}
}
The problem is: my server receives not translated number for some reason. senderIpEndPoint in HandleAdverticement equals 13000 which is my private port number. It seems like my router, ironically, leaves port as it is this time. Do you have any ideas of what can I change to solve my problem?
Your TcpListener doesn't have a public port number. If a router is using NAT to change your source port number along the way, your application will not know about it. This is why port-forwarding is required when you want to make a service available to the public.
What you might be looking for is what is known as TCP hole punching. But in most cases that still requires you to have a public third-party public service that can let the two locations exchange their public endpoint information.
Alternatively Universal Plug and Play (UPnP) might allow you to request the router to port-forward automatically. But this is not something I have worked with myself.
I have searched for 2 days and found many, many questions/answers to what appears to be this same issue, with some differences, however none really seem to provide a solution.
I am implementing a library for controlling a DMX system (ColorKinetics devices) directly without an OEM controller. This involves communicating with an Ethernet-enabled power supply (PDS) connected to my home LAN, through a router, which drives the lighting fixtures. The PDS operates on a specific port (6038) and responds to properly formatted datagrams broadcast over the network.
I can successfully broadcast a simple DMX message (Header + DMX data), which gets picked up by the PDS and applied to connected lighting fixtures, so one-way communication is not an issue.
My issue is that I am now trying to implement a device discovery function to detect the PDS(s) and attached lights on the LAN, and I am not able to receive datagrams which are (absolutely) being sent back from the PDS. I can successfully transmit a datagram which instructs the devices to reply, and I can see the reply coming back in WireShark, but my application does not detect the reply.
I also tried running a simple listener app on another machine, which could detect the initial broadcast, but could not hear the return datagram either, however I figure this wouldn't work since the return packet is addressed to the original sender IP address.
I initially tried implementing via UdpClient, then via Sockets, and both produce the same result no matter what options and parameters I seem to specify.
Here is my current, very simple code to test functionality, currently using Sockets.
byte[] datagram = new CkPacket_DiscoverPDSRequestHeader().ToPacket();
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint ep = new IPEndPoint(IPAddress.Parse("192.168.1.149"), 6039);
public Start()
{
// Start listener
new Thread(() =>
{
Receive();
}).Start();
sender.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
sender.EnableBroadcast = true;
// Bind the sender to known local IP and port 6039
sender.Bind(ep);
}
public void Send()
{
// Broadcast the datagram to port 6038
sender.SendTo(datagram, new IPEndPoint(IPAddress.Broadcast, 6038));
}
public void Receive()
{
Socket receiver = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
receiver.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
receiver.EnableBroadcast = true;
// Bind the receiver to known local IP and port 6039 (same as sender)
IPEndPoint EndPt = new IPEndPoint(IPAddress.Parse("192.168.1.149"),6039);
receiver.Bind(EndPt);
// Listen
while (true)
{
byte[] receivedData = new byte[256];
// Get the data
int rec = receiver.Receive(receivedData);
// Write to console the number of bytes received
Console.WriteLine($"Received {rec} bytes");
}
}
The sender and receiver are bound to an IPEndPoint with the local IP and port 6039. I did this because I could see that each time I initialized a new UdpClient, the system would dynamically assign an outgoing port, which the PDS would send data back to. Doing it this way, I can say that the listener is definitely listening on the port which should receive the PDS response (6039). I believe that since I have the option ReuseAddress set to true, this shouldn't be a problem (no exceptions thrown).
Start() creates a new thread to contain the listener, and initializes options on the sending client.
Send() successfully broadcasts the 16-byte datagram which is received by the PDS on port 6038, and generates a reply to port 6039 (Seen in WireShark)
Receive() does not receive the datagram. If I bind the listener to port 6038, it will receive the original 16-byte datagram broadcast.
Here is the WireShark data:
Wireshark
I have looked at using a library like SharpPCap, as many answers have suggested, but there appear to be some compatibility issues in the latest release that I am not smart enough to circumvent, which prevent the basic examples from functioning properly on my system. It also seems like this sort of basic functionality shouldn't require that type of external dependency. I've also seen many other questions/answers where the issue was similar, but it was solved by setting this-or-that parameter for the Socket or UdpClient, of which I have tried every combination to no avail.
I have also enabled access permissions through windows firewall, allowed port usage, and even completely disabled the firewall, to no success. I don't believe the issue would be with my router, since messages are getting to Wireshark.
UPDATE 1
Per suggestions, I believe I put the listener Socket in promiscuous mode as follows:
Socket receiver = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
receiver.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, true);
receiver.EnableBroadcast = true;
IPEndPoint EndPt = new IPEndPoint(IPAddress.Parse("192.168.1.149"), 0);
receiver.Bind(EndPt);
receiver.IOControl(IOControlCode.ReceiveAll, new byte[] { 1, 0, 0, 0 }, null);
This resulted in the listener receiving all sorts of network traffic, including the outbound requests, but still no incoming reply.
UPDATE 2
As Viet suggested, there is some sort of addressing problem in the request datagram, which is formatted as such:
public class CkPacket_DiscoverPDSRequest : BytePacket
{
public uint magic = 0x0401dc4a;
public ushort version = 0x0100;
public ushort type = 0x0100;
public uint sequence = 0x00000000;
public uint command = 0xffffffff;
}
If I change the command field to my broadcast address 192.168.1.149' or192.168.255.255`, my listener begins detecting the return packets. I admittedly do not know what this field is supposed to represent, and my original guess was to just put in a broadcast address since the point of the datagram is to discover all devices on the network. This is obviously not the case, though I am still not sure the exact point of it.
Either way, thank you for the help, this is progress.
So in actuality it turns out that my issue was with the formatting of the outgoing datagram. The command field needs to be an address on the local subnet 192.168.xxx.xxx, and not 255.255.255.255... for whatever reason this was causing the packet to be filtered somewhere before getting to my application, though WireShark could still see it. This may be common sense in this type of work but being relatively ignorant as to network programming as well as the specifics of this interface it wasn't something I had considered.
Making the change allows a simple UdpClient send/receive to function perfectly.
Much thanks to Viet Hoang for helping me find this!
As you've already noted, you don't need to bind to send out a broadcast but it uses a random source port.
If you adjust your code to not bind the sender, your listener should behave as expected again:
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
sender.EnableBroadcast = true;
Thread read_thread;
public Start()
{
// Start listener
read_thread = new Thread(Receive);
read_thread.Start();
}
The issue you've bumped into is that the operating system kernel is only delivering packets up to one socket binder (first come first serve basis).
If you want true parallel read access, you'll need to look into sniffing example such as: https://stackoverflow.com/a/12437794/8408335.
Since you are only looking to source the broadcast from the same ip/port, you simply need to let the receiver bind first.
If you add in a short sleep after kicking off the receive thread, and before binding the sender, you will be able to see the expected results.
public Start()
{
// Start listener
new Thread(() =>
{
Receive();
}).Start();
Thread.Sleep(100);
sender.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
sender.EnableBroadcast = true;
// Bind the sender to known local IP and port 6039
sender.Bind(ep);
}
Extra note: You can quickly test your udp sockets from a linux box using netcat:
# echo "hello" | nc -q -1 -u 192.168.1.149 6039 -
- Edit -
Problem Part #2
The source address of "255.255.255.255" is invalid.
Did a quick test with two identical packets altering the source ip:
https://i.stack.imgur.com/BvWIa.jpg
Only the one with the valid source IP was printed to the console.
Received 26 bytes
Received 26 bytes
I have a need to talk to multiple devices on a private LAN using a proprietary UDP protocol. In a production setting we have a industrial PC running a C++ application that can connect to multiple devices and communicate freely with them. I am trying to duplicate that communication using C# for a windows application that technicians, testers and others would be using. I have probably done this myself a thousands times in c++ but c# seems to be giving me all sorts of fits.
I have one UDP listener listening on Any IP and specific Port. This port is different from the device command port. This receives a periodic heartbeat from each device. From this communication I am able to get the specific IP and command Port for that device. The program maintains a list of devices and displays that lists to the user. The user can then select a specific device and inspect it more for more details.
If there are several devices with the same port number the program will not be able to inspect those devices at the same time. When the user selects the device the program creates a new instance of the UdpClient. In pseudo-code form:
udpConnection = new UdpClient();
udpConnection.ExclusiveAddressUse = false;
udpConnection.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpConnection.Client.Bind(localEndpoint);
udpConnection.Client.Connect(remoteEndpoint);
Local Endpoint is the Local interface IP and the Device Port Number of the machine the application is running on. Remote EndPoint is the Device IP and Device Port that the application wants to inspect further.
As anyone had similar issues and what have you done to get around it?
Thanks in advance
Update sample network diagram and further explanation:
Network Diagram
In the image I will be able to have two windows viewing Device A and C or B and C simultaneously with no issues. However if I have Device A and C the window that I opened second will not get any communications updates until I close the first window. If I "sniff" the network with WireShark I see all the communications as I would expect.
Code Snippet:
private void ClientThread()
{
IPEndPoint myEndPoint;
myLogger = LogManager.GetLogger("ClientLogs");
myLogger.Debug("Client Started!");
IPAddress ClientAddress = System.Net.IPAddress.Parse(ClientIP);
myIP = "10.0.0.4"; // Currently hard-coded local interface IP
IPAddress thisAddress = System.Net.IPAddress.Parse(myIP);
ClientEndPoint = new IPEndPoint(ClientAddress, Convert.ToInt32(ClientPort));
myEndPoint = new IPEndPoint(thisAddress, Convert.ToInt32(ClientPort)); // Both forms launch but only the first one will receive data.
//myEndPoint = new IPEndPoint(thisAddress, 0); // Both forms will launch but no data received (packets do show being received in wireshark)
//myEndPoint = new IPEndPoint(IPAddress.Any, ClientPort); // Both forms launch but only the first one will receive data.
try
{
myUDP = new UdpClient();
myUDP.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); // "Only one usage of each socket address (protocol/network address/port) is normally permitted" Exception when removed.
myUDP.ExclusiveAddressUse = false; // No difference if this is removed
myUDP.Client.Bind(myEndPoint); // Neither form will receive data if this is removed
myUDP.Client.Connect(ClientEndPoint); // removing this will allow the forms to launch but again the only the first will receive data
}
catch (Exception ex)
{
myUDP = null;
myLogger.Fatal(String.Format("Error in setting up UDP Client: {0}", ex.Message));
return;
}
myLogger.Debug(String.Format("Attempt to connect to : {0} on {1}", ClientIP, Convert.ToInt32(ClientPort)));
byte[] bytes = new byte[1452];
try
{
while (ThreadLoop)
{
IPEndPoint newEndPoint = new IPEndPoint(IPAddress.Any, 0);
Byte[] receiveBytes = myUDP.Receive(ref newEndPoint);
ParseProtocolPacket(ref receiveBytes); // Code to parse the data received
}
}
catch (Exception Ex)
{
myLogger.Debug("Client Socket Other Error: " + Ex.Message);
}
}
I think your problem is here:
udpConnection.Client.Bind(localEndpoint);
This line, if I understand correctly, is telling it to use the same local port to make the outbound request. But you already have another UdpClient listening on that port, so Windows won't know which one to send the traffic to (or it just sends it to the first one).
You should be able to just not use Bind() here. Without it, when you call Connect(), it will assign a random local port, which is the way most outbound network requests work.
Or if you need to specify the network interface, then pass 0 for the port and Windows will assign one:
localEndpoint = new IPEndPoint(ipAddress, 0);
I'm using a UdpClient to receive and send multicast traffic, but I'm having a problem when a new network interface becomes operational while the application is up and running.
The UdpClient is created in my application when the interface becomes operational (plug in network cable raises NetworkChange.NetworkAddressChanged), it binds to the static IP of the interface, and the expected IGMP packets are visible in wireshark on that interface, but the UdpClient instance never reports there is any data available.
The issue also appears to be present if you create the UdpClient before the cable is connected.
I've tried setting SocketOptionName.MulticastInterface, but that should only concern sending multicast traffic, not receiving... Example for this here: https://support.microsoft.com/en-us/kb/318911
Here is a console app that exhibits this issue. While this app is running, I connect the Ethernet cable and Wireshark shows the IGMP join group packets from this app, and incoming multicast traffic from another computer. If I have the cable already plugged in and start the app, it receives all of the traffic I expect.
class Program
{
static UdpClient udpClient;
static IPAddress bindAddress = IPAddress.Parse("192.168.101.220");
static IPAddress groupListenAddress = IPAddress.Parse("239.255.0.1");
static int port = 9999;
static bool shouldRun = true;
static Thread thread;
static void Main(string[] args)
{
udpClient = new UdpClient();
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, true);
IPEndPoint localEndPoint = new IPEndPoint(bindAddress, port);
udpClient.Client.Bind(localEndPoint);
udpClient.JoinMulticastGroup(groupListenAddress);
thread = new Thread(runThread);
thread.Start();
Console.WriteLine("Press Enter to exit.");
Console.ReadLine();
shouldRun = false;
thread.Join(100);
}
private static void runThread(object obj)
{
while (shouldRun)
{
if (udpClient.Available > 0)
{
IPEndPoint endPoint = null;
byte[] buffer = udpClient.Receive(ref endPoint);
Console.WriteLine("Received Message from: {0} Length: {1}", endPoint, buffer.Length);
}
Thread.Sleep(10);
}
}
}
Note that IGMP messages are sent by your host OS, not by your application. If the OS sees a join for a multicast address for the first time it will send out IGMP messages. If another process wants to join the same address as well, new IGMP message may or may not be sent.
Also all kinds of network components (in particular routers, but also Powerline adapters use IGMP snooping to find out where to send multicast traffic, and they often get it wrong. There are two incompatible versions of IGMP and some devices support only one version and some translate between versions in a strange way. This is a big mess.
To make it all really horrible, most devices, including your local host OS, have a time dependent behavior. This makes analyzing problems really difficult since you can never draw hard conclusions, because at the moment it may work just by chance.
Independent of IGMP, the bind() statement is confusing for UDP. On Linux bindign to an IP address will filter all incoming UDP packets and you will only receive packets going to this specific IP address. To receive multicast traffic on Linux you usually have to bind to 0.0.0.0. But I assume you are using Windows, where binding to an IP address of a local adapter is the right thing. Then you will receive mutilcast traffic going to this adapter.
Hi I am using TCPCLient and TCPlitner to transmit data but i am getting error not to connect
below is my Code
private void button1_Click(object sender, EventArgs e)
{
TcpClient tcpc = new TcpClient("192.168.21.46", 10);
NetworkStream nts = tcpc.GetStream();
if (nts.CanWrite)
{
Byte[] sends = System.Text.Encoding.ASCII.GetBytes(textBox1.Text.ToCharArray());
nts.Write(sends, 0, sends.Length);
nts.Flush();
}
}
private void button2_Click(object sender, EventArgs e)
{
TcpListener myListener = new TcpListener(10);
myListener.Start();
while (true)
{
//Accept a new connection
Socket mySocket = myListener.AcceptSocket();
if (mySocket.Connected)
{
//make a byte array and receive data from the client
Byte[] receive = new Byte[64];
int i = mySocket.Receive(receive, receive.Length, 0);
char[] unwanted = { ' ', ' ', ' ' };
string rece = System.Text.Encoding.ASCII.GetString(receive);
label1.Text = rece.TrimEnd(unwanted);
}
}
}
this two buttons i have added in the same form and Ip apddress which is mentioned is my systems IP Address. Can anyone tell me why this Happen. Even I remove firewall setting also.
First of all your UI will hang on button 2 click because it's stuck on the while(true) loop so use BeginAcceptSocket(IAsyncResult r, Object state) for async.
Second you must use the loopback address or otherwise the firewall should block the port 10 assuming that it's not open. Also the TcpListener(int port) is obsolote and its better to use the TcpListener(IPAddress localddr, int port) and use both the loopback address.
I'm assuming you have two different programs and one is listening while the other is sending. If you don't, separate them out. I'm thinking you have a networking issue but can't say precisely why it's blocked.
You're using port 10, which generally is too low for arbitrary application uses even if it's not currently occupied. If you're building a custom protocol, try to listen on a port above approximately 1000 (more a rule of thumb). You can look here http://technet.microsoft.com/en-us/library/cc959828.aspx or google for "tcp well known ports" for more details and to ensure you don't have a collision.
Try running your TCP listener, then open a command prompt and typing the following
telnet localhost 10
or use the port number you change 10 to. I tried your code and was able to connect to port 10 without issue. If you don't have the "telnet" program you can turn the feature on in your Windows. (search "feature" and choose "turn windows feature on or off" then turn "Telnet Client" on)
If the telnet program connects, you'll know that the issue isn't connectivity related. If the telnet program fails to connect then you'll know something is still blocking that port. Try a different port and re-test connectivity. Once telnet connects, you can then focus on the TCP client portion of your program.