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).
Related
I want to send 5 messages from port 7021 to listener of port 7022.
This means that single client send multiple messages to listener.
Following is the implementation:
string message = "787814014E612096";
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("192.168.0.126"), 7021);
var endpoint = new IPEndPoint(IPAddress.Parse("192.168.0.126"), 7022);
// Create a TCP/IP socket.
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sender.Bind(endpoint);
sender.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}", sender.RemoteEndPoint.ToString());
int index = 1;
while (index < 6)
{
Console.WriteLine("Send packet: " + index);
byte[] msg = Encoding.ASCII.GetBytes(message);
int bytesSent = sender.Send(msg);
Thread.Sleep(2000);
index = index + 1;
}
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
Any help in this regard will be appreciated.
Some key points:
Use TcpClient and TcpListener instead of sockets.
Use the Task Async Pattern instead of Async callbacks.
Use the OS to allocate a source port instead of allocating one manually.
Use Task.Delay() instead of Thread.Sleep();
The following line, asks the operating system to send the data.
int bytesSent = sender.Send(msg);
However, you have no way of guaranteeing that the OS will send the data immediately, it can, and sometimes will hang on to that data and send it later.
You also need to be checking bytesSent to find out how many bytes were placed in the outbound queue.
Using TcpClient and the NetworkStream that comes with TcpClient will alleviate a lot of the Socket edge cases that you will encounter.
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'm trying to send out a multicast packet then receive the response that comes back (there should only be one response.) I can send the packet, and wireshark shows the reply but my program never receives it. I've tried a few different things but this is the current state of my non-functioning code.
IPEndPoint epReceive = new IPEndPoint(IPAddress.Any, 5355);
IPEndPoint epSend = new IPEndPoint(IPAddress.Parse("224.0.0.252"), 5355);
UdpClient sendClient = new UdpClient();
sendClient.ExclusiveAddressUse = false;
sendClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
sendClient.Client.Bind(epReceive);
sendClient.Send(packet, packetLength, epSend);
byte[] buffer = sendClient.Receive(ref epReceive);
sendClient.Close();
This code just hangs on the sendClient.Receive() line. I realise this code is currently blocking and could/should be threaded, but for the purposes it's being used for it's not a concern.
I've been working with UDP sockets quite a lot recently. I've read that UDP does not have an internal buffer. That means if a packet arrives and there is no one waiting for it, it gets dumped. I've thought of a situation which's occurence is very unlikely. But if it occurs, it can cause problems.
byte[] buffer = new byte[1024];
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.Bind(...);
while (true)
{
EndPoint remote = new IPEndPoint(IPAddress.Any, 0);
socket.ReceiveFrom(buffer, ref remote);
socket.SendTo(remote, new byte[] { 1, 2, 3, 4 });
}
What if while SendTo is executed, which is a non-async method (so it blocks the thread it's run in until it's done, i.e. done sending the data), another packet from a different host arrives? As the ReceiveFrom method is not being executed, will the packet get dumped?
Just assuming "yes", I've thought of using asynchronous sockets. It would look like this:
Socket socket;
byte[] buffer;
void StartServer()
{
buffer = new byte[1024];
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.Bind(...);
EndPoint remote = new IPEndPoint(IPAddress.Any, 0);
StartReceive();
}
void StartReceive()
{
socket.BeginReceiveFrom(buffer, 0, buffer.Size, SocketFlags.None, ref remote, OnReceive, null);
}
void OnReceive(IAsyncState state)
{
EndPoint epRemote = new IPEndPoint(IPAddress.Any, 0);
socket.EndReceiveFrom(state, ref epRemote);
socket.BeginSendTo(new byte[] { 1, 2, 3, 4 }, 0, 4, SocketFlags.None, epRemote, null, null);
StartReceive();
}
When the OnReceive method is called by socket.BeginReceiveFrom when it's done, its code gets executed. Since this code uses BeginSendTo, it doesn't block the thread. But what if a packet arrives before OnReceive can call StartReceive? Will it be lost?
So my question:
Does a UDP packet get buffered at all, and if yes, for how long?
No, the internals of the framework will ensure that the packets are in a que until they get parsed. This is usually achieved by using a buffer that saves the packets for a period of time until the reciever actually gets the packets.
There are multiple layers that ensure this, for more information and because you use the application layer of OSI you should study OSI to understand these concepts deeply.
UDP does get buffered at lower levels of the system, but when the buffer is full and more UDP packets arrive, they are dropped. UDP packets can be dropped anywhere between sender and receiver. If you want to be sure you are receiving everything, you should keep an ID of some sort for each packet sent/received, in a specific order, so you can see if something is missing and request it being sent again.