I'm writing a C# program that needs to send the same data to multiple specific recipients. I can't use multicast because that sends the data to everyone listening on the multicast address.
My current solution is to just iterate through the recipients and send the data to each of them separately but I'm looking for something a little more efficient.
Here's my current solution:
public void SendToMultiple(IPAddress[] Recipients, byte[] Data)
{
UdpClient Client = new UdpClient();
foreach(IPAddress Recipient in Recipients)
{
Client.Send(Data, Data.Length, new IPEndPoint(Recipient, PORT));
}
Client.Close();
}
To the best of my knowledge you can either use Unicast, Multicast or Broadcast.
Since you are only interested in sending to a particular set of clients, I can only recommend Unicast as the other two will send to those also listening.
The only thing I can think of to make it more efficient is to put the code in maybe a Parallel.Foreach loop and create the UdpClient in there and then send the data out?
public void SendToMultiple(IPAddress[] Recipients, byte[] Data)
{
Parallel.ForEach(Recipients,
Recipient =>
{
UdpClient Client = new UdpClient();
Client.Send(Data, Data.Length, new IPEndPoint(Recipient, PORT));
Client.Close();
});
}
Related
I am new to multicast programming. So far I can successfully send and receive multicast messages from two separate processes (a sender and a receiver). My problem is with the receiver...
ReceiverCode:
private static void ReceiveMulticastMessages()
{
var groupEndPoint = new IPEndPoint(IPAddress.Parse("238.8.8.8"), 23888);
var localEndPoint = new IPEndPoint(IPAddress.Any, 23888);
using (var udpClient = new UdpClient())
{
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Client.Bind(localEndPoint);
udpClient.JoinMulticastGroup(groupEndPoint.Address, localEndPoint.Address);
while (true)
{
var remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
var bytes = udpClient.Receive(ref remoteEndPoint);
var message = Encoding.ASCII.GetString(bytes);
Console.WriteLine(message);
}
}
}
The above code works as long as I specify port 23888 for the localEndPoint. If I change the local port number, no messages are received. I would prefer to set it to 0 so the OS could choose the port. Why can I not specify a different local port than that of multicast group?
Assuming the local endpoint port must match the multicast group port, how does a client deal with a local port conflict?
On the flip side, how can an application (a multicast sender) choose a multicast group port such that any subscribers will not have a port conflict?
When sending any UDP message (not just muticast messages), the port that the sender sends to must match the port that the receiver is listening on. That's how messages get to the right place. If a message is sent to a port other that the one the receiver is bound to, the receiver won't get it.
So a port number needs to be defined that the receiver(s) will listen on and the server will send to.
I have an embedded Ethernet interface (Lantronix XPort) that responds to a UDP broadcast with its identifying information.
I am able to multicast the "magic packet" and datagrams are received by the listener correctly, however I also need to find out what IP Address send that response datagram. If it were TCP, I would do socket.RemoteEndPoint, but that throws an exception when applied to a UDP socket.
public class Program
{
public static void Main(string[] args)
{
// magic packet
byte[] magicPacket = new byte[4] { 0, 0, 0, 0xf6 };
// set up listener for response
Socket sendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// EDIT: Also, had to add this to for it to broadcast correctly
sendSocket.EnableBroadcast = true;
IPEndPoint listen_ep = new IPEndPoint(IPAddress.Any, 0);
sendSocket.Bind(listen_ep);
// set up broadcast message
EndPoint send_ep = new IPEndPoint(IPAddress.Parse("192.168.255.255"), 30718);
sendSocket.SendTo(magicPacket, magicPacket.Length, SocketFlags.None, send_ep);
DateTime dtStart = DateTime.Now;
while (true)
{
if (sendSocket.Available > 0)
{
byte[] data = new byte[2048];
// throws SocketException
//IPEndPoint ip = sendSocket.RemoteEndPoint as IPEndPoint;
sendSocket.Receive(data, SocketFlags.None);
if (data.Length > 4)
{
PrintDevice(data);
}
}
if (DateTime.Now > dtStart.AddSeconds(5))
{
break;
}
Console.WriteLine(".");
Thread.Sleep(100);
}
// wait for keypress to quit
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
Any thoughts? Is there a better strategy to reading the response datagrams that would let me ascertain the Remote IP Address?
EDIT:
As is typical, the minute I post on SO, a moment of clarity hits me.
Turns out I can just do this:
EndPoint remote_ep = new IPEndPoint(IPAddress.Any, 0);
// Use ReceiveFrom instead of Receieve
//sendSocket.Receive(data, SocketFlags.None);
sendSocket.ReceiveFrom(data, ref remote_ep);
And remote_ep now contains the remote endpoint information!
Take a look at ReceiveFrom instead of Receive, it will let you pass in a reference to an Endpoint.
What about Asynchronous socket?I didn't find any way to get the remote IP address. (Asynchronous method ReceiveFromAsync is my only option in wp8)
EndPoint remote_ep = new IPEndPoint(IPAddress.Any, 0); // Use ReceiveFrom instead of
sendSocket.Receive(data, SocketFlags.None);
sendSocket.ReceiveFrom(data, ref remote_ep);
i think it works for IP but it fails for port number
if you would notice
try chaging 0 to something else like 6530 4expl
it system will would generate it's random port number
Any ideas to why is it ?
P.S. Any ideas how can i change my user name here .... ?
FOUND IT : the abstract class only needed for representation of port it is in value not out
since there's no bind done before hand this operation ref EndPoint needed to represent the sender. Meaning that it is there to show senders port and IP not to specify from where to get the communication. And EndPoint instantiation is really just a formality seems like it is overriden by system with senders address anyway. I think it has to do somethign with the way UDP protocol works.
But all in all the ref EndPoint is there only shows where u got the packet from and only it does not specify where u want u'r commuicatino to be from.
Hello I am developing sample application for demonstration of udp client to send data from client to server. I have created console application and below is my code.
class Program
{
static void Main(string[] args)
{
senddata();
while (true)
{
try {
UdpClient udpClient = new UdpClient(9999);
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
string result;
result = returnData.ToString();
}
catch(Exception e)
{
}
}
void senddata()
{
UdpClient udpClient = new UdpClient(9999);
udpClient.Connect("10.170.84.163", 9999);
Byte[] senddata1 = Encoding.ASCII.GetBytes("Hello World");
udpClient.Send(senddata1, senddata1.Length);
}
}
}
whenever Byte[] receiveBytes is executed i get my empty black screen and nothing is going to happen. Can someone tell me how to fix this? Any help would be appreciated. Thank you.
There are several issues here:
You send data to udp port (via senddata()) before starting a listener on that port, and you do this only once, so there is no chance listener might receive it.
There is no need to bind UdpClient to specific port when sending data, especially to the same port on which you are listening with another UdpClient. Just use UdpClient udpClient = new UdpClient(); to let it use any available port for sending.
Since you are testing - there is no need to send data to your external ip, send to loopback interface instead: udpClient.Connect(IPAddress.Loopback, 9999);.
UdpClient implements IDisposable, so dispose it when you are done.
Your while (true) loop will not work, because you don't dispose UdpClient, so on second iteration of the loop, second UdpClient will try to bind to the same 9999 port and fail, because there is already listener (which you didn't dispose) on that same port.
Your code with fixes above (obviously that is not "production" code so I won't add things like cancellation and so on, only fixes to be able to see message is coming):
static void senddata() {
// send message every 100 ms
while (true) {
// wrap in using
using (UdpClient udpClient = new UdpClient()) {
// loopback
udpClient.Connect(IPAddress.Loopback, 9999);
Byte[] senddata1 = Encoding.ASCII.GetBytes("Hello World");
udpClient.Send(senddata1, senddata1.Length);
}
Thread.Sleep(100);
}
}
static void Main(string[] args) {
// run sending in background
Task.Run(() => senddata());
try {
// wrap in using
using (UdpClient udpClient = new UdpClient(9999)) {
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
// move while loop here
while (true) {
// this blocks until message is received
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
Console.WriteLine(returnData);
}
}
}
catch (Exception e) {
// do something meaningful
}
}
It doesn't look like you're outputting the received string.
Something like this....
string result;
result = returnData.ToString();
Console.WriteLine(result);
Try changing the following:
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
To use the port 9999 rather than a random port. I'm honestly somewhat surprised that doesn't throw an exception.
Note that binding to a random port as a server is not atypical but the remote end will need some way to discover that random port I..E. the way ftp uses a second port for actual file data transfer, that port number is sent as part of the message starting the transfer.
I followed link to create an Async TCP server. However, all examples cover only sending data as a response to receive. My question is how to Push data to a certain TCP client.
Let us say tat a byte[] needs to be sent/pushed to client Id 1.
How can I achieve this using SocketAsyncEventArgs architecture?
I know I have to keep a list of active connections and client ids. What should this list look like in order to push data?
public bool Send(Socket socket, byte[] message)
{
SocketAsyncEventArgs completeArgs = new SocketAsyncEventArgs();
if (socket.Connected)
{
// Prepare arguments for send/receive operation.
completeArgs.SetBuffer(message, 0, message.Length);
completeArgs.UserToken = socket;
completeArgs.AcceptSocket = socket;
completeArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnIOCompleted);
// Start sending asyncronally.
socket.SendAsync(completeArgs);
}
return true;
}
I try to receive six messages from UDP unicast clients. Receiver looks like:
UdpClient udpclient = new UdpClient();
IPEndPoint localEp = new IPEndPoint(IPAddress.Parse(ClientIP), ClientPort);
udpclient.Client.Bind(localEp);
udpclient.Client.ReceiveTimeout = 10000;
bool isTimeExpired = false;
while (!isTimeExpired)
{
byte[] buffer;
try
{
buffer = udpclient.Receive(ref localEp);
}
catch (SocketException)
{
isTimeExpired = true;
continue;
}
// Deserialize
// ...
}
udpclient.Close();
Program works, but sometimes I don't receive 6 messages (2 or 3). Sender application:
UdpClient client = new UdpClient();
IPEndPoint remoteep = new IPEndPoint(IPAddress.Parse(ClientIP), ClientPort);
// Serialize
// ...
stream.Position = 0;
byte[] data = new Byte[stream.Length];
stream.Read(data, 0, Convert.ToInt32(stream.Length));
client.Send(data, data.Length, remoteep);
stream.Close();
client.Close();
I run 6 instances of sender application at the same machine (and one instance of receiver). I need to receive messages from every sender (six messages total) all the time. Where is my mistake?
Thank you very much!
It's UDP. There's no guarantee you'd receive any of the datagrams that were sent. UDP is, by design, unreliable. The "User" in the UDP might as well stand for "Unreliable" instead. :)
FYI: there also is no guarantee that you'll receive only one copy of any given datagram that was sent. There is also no guarantee that the datagrams will arrive in the same order in which they were sent.
If you need that kind of reliability, then you need TCP, not UDP (or you need to do a bunch of extra work to re-invent the TCP wheel).