Get the IpAddress on which we received an UDP Multicast request - c#

I'm using an UdpClient to read data from a multicast group.
It's configured like this:
m_udpClientReceiver = new UdpClient();
m_receivingEndPoint = new IPEndPoint(IPAddress.Any, m_port);
m_udpClientReceiver.ExclusiveAddressUse = false;
m_udpClientReceiver.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
m_udpClientReceiver.ExclusiveAddressUse = false;
m_udpClientReceiver.Client.Bind(m_receivingEndPoint);
m_udpClientReceiver.JoinMulticastGroup(m_multicastAddress, 255);
and I read it with:
Byte[] data = m_udpClientReceiver.Receive(ref m_receivingEndPoint);
I've several network cards(two LAN, one wifi), that are bound on differents subnets. I need to know on which network card(which ip in fact) the request has been received.
How can I achieve this?
Thank you!

As an alternative have you considered not joining a multicast group? You can send and receive multicast packets just as easily using the standard UDPClient class. i.e.
UdpClient.Send(byte[] dgram, int bytes, IPEndPoint endPoint)
where endPoint = new IPEndPoint(IPAddress.Broadcast, <port number>). And on the receive still using:
Byte[] data = m_udpClientReceiver.Receive(ref m_receivingEndPoint);
where m_receivingEndPoint is now correctly set? I've just tested this and it works fine.

I'm finally using the BeginReceive method(async), and I'm giving as context the ip on which it's bound

Related

C# Receive Multicast UDP in multiple programs on the same machine?

Thanks in advance for any help.
There is a program, not written by me that sends UDP multicast packets of info on the local LAN. I've looked the source and it appears they are correctly setup to multicast. This program is WSJT-X which if you are a Ham operator you might have heard of.
The UDP packets contain over the air signal decodes so lots of other programs including mine are interested in these packets.
The problem I'm having is that my UDP receive seems to consume the messages so no other software running on the same machine seems to receive them once my test software starts up.
Here is simple receiver:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace ReadUDP
{
internal class Program
{
private static void Main(string[] args)
{
// Setup
int port = 2237;
var multicastIP = IPAddress.Parse("225.0.0.1");
// Create endpoints
var remoteEndPoint = new IPEndPoint(multicastIP, port);
var localEndPoint = new IPEndPoint(IPAddress.Any, port);
// Create and configure UdpClient
var udpclient = new UdpClient();
udpclient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpclient.ExclusiveAddressUse = false;
udpclient.Client.MulticastLoopback = true;
udpclient.MulticastLoopback = true;
// Bind, Join
udpclient.Client.Bind(localEndPoint);
udpclient.JoinMulticastGroup(multicastIP, IPAddress.Any);
Task.Run(() =>
{
IPEndPoint sender = new IPEndPoint(0, 0);
while (true)
{
var recvBuffer = udpclient.Receive(ref sender);
var recvStr = Encoding.UTF8.GetString(recvBuffer);
Console.WriteLine("--------------------------------------------------------------------------");
Console.WriteLine($"From:{sender} Data:{recvStr}");
Console.WriteLine("--------------------------------------------------------------------------");
}
});
Console.ReadLine();
}
}
}
This simple program receives the data sent by WSJT-X just fine.
If I clone this project to a new directory, build a new copy of the program and run it, the copy never receives any of the broadcast data while the first copy is running. Only the first running copy gets data.
If I shutdown the first copy then the second copy starts to receive the data.
This acts like the first copy is consuming the message and no other clients receive it. I'm trying to prevent that. I just want to in effect, "peek" at the messages and allow other clients to receive them.
I've tried a a bunch of different options and settings, I've looked at many examples but I have not been able to solve this issue.
Any help would be greatly appreciated.
For those of you that don't have WSJT-X, the following simple UDP sender will send UDP packets:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace ReadUDP
{
internal class Program
{
private static void Main(string[] args)
{
// Setup
int port = 2237;
var multicastIP = IPAddress.Parse("225.0.0.1");
// Create endpoints
var remoteEndPoint = new IPEndPoint(multicastIP, port);
var localEndPoint = new IPEndPoint(IPAddress.Any, port);
// Create and configure UdpClient
var udpclient = new UdpClient();
udpclient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpclient.ExclusiveAddressUse = false;
udpclient.Client.MulticastLoopback = true;
udpclient.MulticastLoopback = true;
// Bind, Join
udpclient.Client.Bind(localEndPoint);
udpclient.JoinMulticastGroup(multicastIP, IPAddress.Any);
Task.Run(() =>
{
int msgnum = 1;
while (true)
{
var msg = $"Sending message {msgnum++}";
Console.WriteLine("--------------------------------------------------------------------------");
Console.WriteLine($"Send: {msg}");
Console.WriteLine("--------------------------------------------------------------------------");
var bytes = Encoding.UTF8.GetBytes(msg);
udpclient.Send(bytes, bytes.Length, remoteEndPoint);
Task.Delay(2000).Wait();
}
});
Console.ReadLine();
}
}
}
I am doing much the same thing but in VB.net.
WSJT-x runs on my "HamPC" and sends the udp packets to my "Programming" PC for decode.
Program skims the callsigns and looks up the stations Country/State via QRZ's XML service and plays a sound when a new state or country shows up on the band I am listening to.
I have yet to run 2 instances of my program on the "ProgrammingPC" but if I run into what you have I would add code so that the first running instance of my program will rebroadcast all of the packets exactly as received to another port for the second instance of my program to receive.
I found this thread looking for information on finding the Band information in the UDP packets transmitted by WJST-x. I've found and decoded the AudioFreq, TimeStamp and Signal Strength fields easily enough, now I'm scouring the data to locate the Band/Frequency which I need. Was easy in the first generation of my program which repeated read the all.txt file every 15 seconds at 01 16 31 and 41 seconds after the minute and determines which records are new (via simple line counting)
I have Googled high and low but cannot find a published structure of wjst-x's UDP packets - mainly offsets of the fields / how to decode them. I found the fields mentioned above by capturing the UDP packets looking at the contents byte by byte and comparing to the all.txt file for records written during the same transmissions.
The Band/Freq field should be the last one I need.
I believe my suggestion and retransmitting the packets intact to another port for the 2nd instance to receive on will work for you.
Program starts up unware if it is the 1st instance or not. It listen's on the primary port -- If data received on primary uses that port for receive and rebroadcasts the data as received to the 2nd port.
If no data was received on the 1st port it would switch and to listen on the 2nd port and not rebroadcast the data.
Perhaps a bandaid of a workaround but should work.
Best of luck! - 73 ne5B

How to use tcplistener and tcpclient on device and computer with different ip in same Network?

I'm trying to communicate with a modbus device in my network at ip 192.168.1.76. My host computer address is 192.168.1.132. I'm not able to connect to or listen to device ip.
basically i'm using NModbus4 library. I've created a ModbusTCPSlave and attached the tcp listener to it. then i assigned ModbusSlaveRequestReceived event to that slave. but it gives nothing in return when i try to change register values directly from Modscan software.
Main()
{
var masterEndpoint = new IPEndPoint(IPAddress.Parse("192.168.1.132"), 502);
var listener = new TcpListener(IPAddress.Any, 502);
listener.Start();
var slave = ModbusTcpSlave.CreateTcp(255, new TcpListener(masterEndpoint), 10);
slave.ModbusSlaveRequestReceived += Modbus_Request_Event;
slave.Listen();
}
private static void Modbus_Request_Event(object sender, Modbus.Device.ModbusSlaveRequestEventArgs e)
{
//disassemble packet from master
byte fc = e.Message.FunctionCode;
byte[] data = e.Message.MessageFrame;
byte[] byteStartAddress = new byte[] { data[3], data[2] };
byte[] byteNum = new byte[] { data[5], data[4] };
Int16 StartAddress = BitConverter.ToInt16(byteStartAddress, 0);
Int16 NumOfPoint = BitConverter.ToInt16(byteNum, 0);
Console.WriteLine(fc.ToString() + "," + StartAddress.ToString() + "," + NumOfPoint.ToString());
}
I expect to get function code, start address and number of points in console application when any register value is changed
I copied your code. Changed the IP address to my "server" and it worked.
So, the issue you are having is either in the setup of your "server" or in the PLC program.
I thought that I had to do some port forwarding on my router. I did not. It did not make a difference.
Server setup:
Your "server"'s IP address needs to be static. Whether your 'server' is your development system or not. And don't forget when you deploy... Server's IP address has to be static as well (not that it wouldn't be...just saying)
Add an inbound Firewall rule to allow connections to the port, in this case 502, otherwise you'll have to allow access every time you launch/start a test.
PLC program
I am using Click PLC's by Koyo. Not sure if this is the rule for all PLC's or not; but, we had to add a line of code to "write" the values we wanted to pick up off the TCP stream. Without the write, the PLC was not sending out a request to join the TcpListener.
Last:
The code to start your listener only needs to be this:
var listener = new TcpListener(IPAddress.Parse("192.168.1.244"), 502);
listener.Start();
var slave = ModbusTcpSlave.CreateTcp(255, listener, 10);
slave.ModbusSlaveRequestReceived += Modbus_Request_Event;
slave.Listen();

C# UDPClient pass variable as port value

This is my code:
UdpClient server = new UdpClient(5001);
My question is: i want to pass the port value (5001), from an int variable. Is this possible?
Example:
UDPClient server = new UDPClient(intvariable);
Thank you!
The constructor of the UpdClient is Int32 so you can do so.
int variable = value;
UDPClient server = new UDPClient(variable);
Here's the definition of the UpdClient class
You can set up the address and port in the constructor, just take a look at the documentation http://msdn.microsoft.com/en-us/library/system.net.sockets.udpclient%28v=vs.110%29.aspx
So you could have
int portNumber = 12345;
string ipAddress = 127.0.0.1 //You can also use a web address instead.
UDPClient newClient - new UDPClient(ipAddress, portNumber);
Alternatively you can put nothing in the constructor and do the specify a destination when you connect. This allows you to get user input first rather than hard coding the address and port.
int portNumber = 12345;
string ipAddress = 127.0.0.1 //You can also use a web address instead.
UDPClient newClient - new UDPClient();
newClient.Connect(IpTextBox.text(), Convert.ToInt32(portNumberTB.Text() );
Remember if you are reading user input for your address and port then you will need error handling.
The constructor of UdpClient cannot tell the difference between new UdpClient(1234) and
int port = 1234; new UdpClient(port);
For that reason there cannot possibly be a difference. 1234 and port are expressions of the same value. That's the only thing that counts.
Thank you for the answers.
The code you people gave me was correct. My code aswell.
My problem occurs in the declaration of the UDPClient objects. The declaration happens
during the initialization of a windows form application.

c# TCPclient set IP

I'm trying to send a packet using httpclient
TcpClient tc = new TcpClient(ip, 4500);
string s = "A7007000601D3B00";
byte[] arr = new byte[s.Length/2];
for ( var i = 0 ; i<arr.Length ; i++ ){
arr[i] = (byte)Convert.ToInt32(s.Substring(i*2,2), 16);
}
NetworkStream stream = tc.GetStream();
stream.Write(arr, 0, arr.Length);
tc.Close();
The problem is that it sends from port 47109, however i need to send the packet using port 46324. How do i set this?
There is an overload of the TcpClient constructor that allows you to bind it to a specific local IP address and port. See the documentation on MSDN.
The reason the example at Is there a way to specify the local port to used in tcpClient? is not working is probably because the first address on the list is not actually the local machine ip address. Something like this might fix the issue and pull the proper local IP address:
string remoteIP = "x.x.x.x";
IPAddress ipAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList.Where(x => x.AddressFamily == AddressFamily.InterNetwork).First();
IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, 47109);
TcpClient clientSocket = new TcpClient(ipLocalEndPoint);
clientSocket.Connect(remoteIP, 4500);

udp server respond on the basis of the request received from the udp client

I am making a UDP application in which I am able to receive the messages from udp client and sending a result back to the udp client...but now i want to set the udp server responses on the basis of the request...like for example if udp client send "Hello" message to the server then server reacts accordingly that if the client send "world" then server reacts accordingly that....In short my problem is that i am not able to read out the string which i am receiving at the server site.....this is window form application in c#
for example here is the code:
int recv;
byte[] data = new byte[1024];
IPEndPoint endpoint = new IPEndPoint(IPAddress.Loopback, 1235);
Socket newsocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
newsocket.Bind(endpoint);
MessageBox.Show("waiting for a client..");
IPEndPoint sen = new IPEndPoint(IPAddress.Loopback, 5001);
EndPoint tmp = (EndPoint)sen;
recv = newsocket.ReceiveFrom(data, ref tmp);
MessageBox.Show(" message recieved", tmp.ToString());
MessageBox.Show(Encoding.ASCII.GetString(data, 0, recv));
now i want to read out the string which i am receiving at the "recv" integer by which i could able to set the responses accordingly that..Please tell me How can i do that...
see this
link maybe it can help, your code seams to be rigth, but if it is not working try to change the encoding
to compare the data to string you need first convert it to an string with this line of code
Encoding.ASCII.GetString(data, 0, recv)
use like this
recv = newsocket.ReceiveFrom(data, ref tmp);
string receiver = Encoding.ASCII.GetString(data, 0, recv);
if (receiver == "Hello"){"do something"}

Categories

Resources