Losing packets due to occurence of very unlikely situation? - c#

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.

Related

Udp server receive message from external client as if it is from server IP [duplicate]

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.

C#. UDP unicast

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).

Socket stops receiving after X messages

I have a .NET Socket that listens to all TCP requests on the computer, and aggregates them into HTTP requests (where possible).
I have the following problem -
When I access a site (for example - stackoverflow.com) I see in WireShark that there are X (lets say - 12) TCP packets received from the site's host.
But in my code the Socket just stops receiving the messages before the end (after 10 messages)
I have no idea how to fix this, I hope it's something that is limiting the socket in his definition
Here is my code:
public void StartCapturing()
{
try
{
_chosenOutgoingAddress = UserChoosesIpCtrl();
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw,
ProtocolType.IP);
_socket.Bind(new IPEndPoint(_chosenOutgoingAddress, 0));
_socket.SetSocketOption(SocketOptionLevel.IP,
SocketOptionName.HeaderIncluded, true);
_socket.IOControl(IOControlCode.ReceiveAll, _bIn, _bOut);
thrStartCapturing = new Thread(StartReceiving);
thrStartCapturing.Name = "Capture Thread";
thrStartCapturing.Start();
}
catch (Exception ex)
{
//TODO: general exception handler
throw ex;
}
}
The StartCapturing method will initiate the Socket and start the receiving thread with the StartReceiving method (as below0
private void StartReceiving()
{
while (!_stopCapturing)
{
int size = _socket.ReceiveBufferSize;
int bytesReceived = _socket.Receive(_bBuffer,
0,
_bBuffer.Length,
SocketFlags.None);
if (bytesReceived > 0)
{
_decPackagesReceived++;
ConvertReceivedData(_bBuffer, bytesReceived);
}
Array.Clear(_bBuffer, 0, _bBuffer.Length);
}
}
What am I doing wrong?
Ok, I figured it out, so I'm posting here for anyone else who might need it in the future
The .NET Socket class has a property ReceiveBufferSize which determines what is the buffer that the Socket will allow.
My problem was that my code wasn't ASync, or fast enough to clean this buffer, so that the last TCP packets had no more buffer and were ignored.
Increasing the ReceiveBufferSize or make my code ASync (probably better :-)) will fix this.

TCP Socket receiving every second packet

I'm trying to code a basic game, where when one player makes a move, the other receives the packet and vice versa. The problem is, only every second packet is being received. I know it's not the connection because it's consistently the same pattern of missed packets.
My code is as follows:
Socket serverSocket
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Take socket from another window that created it and start receiving
serverSocket = Welcome.MainSocket;
serverSocket.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(OnReceive), null);
//The initial definition of the socket was this (in the Welcome window)
//MainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//MainSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
//MainSocket.Bind(new IPEndPoint(OwnLocal, OwnPort));
//MainSocket.Connect(Address, OppositePort);
}
private void OnReceive(IAsyncResult ar)
{
OnlineData Data = OnlineData.FromByte(Buffer);
//Do stuff with data on UI thread
if (Data is MoveData)
{ App.Current.Dispatcher.Invoke((Action)delegate
{
((MoveData)Data).Sync(Game, Me == Game.PlayerOne ? 1 : 2);
});
}
//End receive and start receiving again
serverSocket.EndReceive(ar);
serverSocket.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(OnReceive), null);
}
//Called each time the player makes a move
void SocketSend(OnlineData Data)
{
serverSocket.Send(Data.ToByte());
}
Any ideas why this would ever happen in my case or in any other situation? Thanks!
The immediate thing I can see is that you aren't calling EndReceive, which means you aren't processing the critical return value from that method: the number of bytes received. I expect your data is being combined and multiple messages are being received in a single "receive" call (TCP is stream based, not message based).
This also means you aren't seeing any exceptions that you should know about.
Additionally, not calling End* methods can cause leak issues - you are very much meant to call End* methods. Or switch to the newer async IO API.
What was happening was that I had two different AsyncCallbacks for BeginRecieve, one from the original window ("Welcome") in which the socket was created, and one for this window. Each time the other computer sent a message, the AsyncCallback that receieved the data was alternating between the two.
Moral of this story: Only have one AsyncCallback for a socket unless you want to only receive every second packet.

UDP sometimes can't receive anything

I have a C# application that receives UDP data from a remote host. I find that sometimes my socket receives nothing and I cant seem to find any clues as to why!
Wireshark tells me my data is being sent from the remote device correctly. I cant seem to get why sometimes I can receive fine, and sometimes I can't.
I don't get any exceptions, but OnRecieve never gets called
Here is my code in case it helps:
class cUdpRx
{
private Thread rxThread = null;
private Socket UdpSocket;
private IPEndPoint localEp;
byte[] byData;
//rxbytes event
public delegate void OnRxBytesEventHandler(byte[] rxBuf);
public event OnRxBytesEventHandler OnRxBytesEvent;
/// <summary>
/// Creates the udp socket
/// </summary>
/// <param name="Port"></param>
/// <returns></returns>
public bool CreateSocket(int Port)
{
try
{
byData = new byte[1500]; //create our buffer
UdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
UdpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
localEp = new IPEndPoint(IPAddress.Any,Port);
UdpSocket.Bind(localEp);
UdpSocket.BeginReceive(byData,0,byData.Length, SocketFlags.None, new AsyncCallback(OnRecieve), UdpSocket);
return true; //seemed to work ok
}
catch
{
Dispose();
return false; //something went wrong, abort
}
}
private void OnRecieve(IAsyncResult iar)
{
byte[] rxData;
int nBytesRec = 0;
Socket socket = (Socket)iar.AsyncState;
try //in case something else has already disposed of the socket
{
nBytesRec = socket.EndReceive(iar);
}
catch
{
Debug.WriteLine("cant access udp rx socket");
}
try
{
if (nBytesRec > 0)
{
rxData = new byte[nBytesRec];
Array.Copy(byData, rxData, nBytesRec); //copy exact data into new array
OnRxBytesEvent(rxData);
}
if(!killThreads)
UdpSocket.BeginReceive(byData, 0, byData.Length, SocketFlags.None, new AsyncCallback(OnRecieve), UdpSocket);
}
catch(SocketException se)
{
Debug.WriteLine(se.ToString());
}
}
Any help would be really appreciated as its stopping me from going forward with my project. Thanks
UPDATE
It seems like using IPAdress.any is the problem. If I change:
localEp = new IPEndPoint(IPAddress.Any,Port);
to
localEp = new IPEndPoint(IPAddress.Parse("192.168.0.33"),Port);
where 192.168.0.33 is the IP address of my computer, it receives data every time.
Can anyone explain why?
It is quite useful to use IPAddress.any and receive from both wireless and wired connections.
IPAddress.any is equivalent to 0.0.0.0 and according to MSDN it should receive on all network interfaces.
The usual cause of such problems is not processing packets fast enough. They fill up socket receive buffer and kernel starts dropping them.
Increase socket receive buffer size to accommodate traffic bursts.
Remove everything non-essential from the fast socket reading path.
Consider simple iterative approach bellow instead of working against thread pool:
rxData = new byte[nBytesRec];
while ( !time_to_stop ) {
int len = socket.Receive( rxData );
OnRxBytesEvent( rxData, len );
}
Your code comments mention multicast. Note that you need to add explicit group membership for that, and the fact that you join a multicast group on an interface (either explicitly or as decided via routing table), so if you want to listen for multicast data on two interfaces you need two sockets.
I just got the same problem and resolve it by set timeTolive to big data.
_client = new UdpClient();
_client.Client.Bind(new IPEndPoint(IPAddress.Any, targetURI.Port));
_client.JoinMulticastGroup(IPAddress.Parse(targetURI.Host) , 250);
timeToLive = 250, it works.
timeToLive = 50 , works or not work alternate happened.
timeToLive = none or 0, not work.

Categories

Resources