Hi,
I have written a small application that sends and receives UDP
datagrams of a certain size at a certain speed; both work fine on 1
host (sending to localhost and receiving there also). The aim of the
application is to test packet loss over a direct ethernet connection
in a variety of physical conditions.
When I test the applications on 2 different host, the receiver is not
able to receive the packets rapidly enough an easily 5% gets lost at
only 0.5 Mbit/sec on a direct point-to-point ethernet connection.
Using a packet sniffer I can see that all the packets arrive correctly
at the receiver's side. It's a problem of my .NET program not being
able to receive the datagrams rapidly enough. I have tried 2 ways :
with UDPClient.Receive and with asynchronous callback on a socket and
BeginReceiveFrom/EindReceiveFrom. The former gives better results than
the latter.
Is there a solution to this, more specifically, is there a way to
increate the buffer size at the receiver on a lower level in the .NET
software stack?
I am getting desperate for a solution.
I need to process at least 6 Mbit/sec without big packet loss in
"perfect" physical conditions.
Below the code that I have been using (2 ways).
Thanks for your help,
Emmanuel Lambert
----------------------------------------
// 1) Using UDPClient.Receive
-------------------------
public void receiveStream()
{
try
{
iUdpReceiveClient = new UdpClient(iPort);
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any,iPort);
iPacketsReceived = 0;
iReceivedPacketsLost = 0;
iReceivedPacketsLostPct = 0;
while (!iStop)
{
Byte[] receiveBytes = iUdpReceiveClient.Receive(ref
RemoteIpEndPoint);
long packetVolgnr = buildLong(receiveBytes);
iPacketsReceived++;
iReceivedPacketSize = receiveBytes.Length;
iReceivedPacketsLost = packetVolgnr - iPacketsReceived;
if (packetVolgnr != 0)
{
iReceivedPacketsLostPct =
Math.Round((double)iReceivedPacketsLost / (double)packetVolgnr *
100.0, 2);
}
}
}
catch (Exception e)
{
if ( (iFncSendError != null) && (!iStop) )
{
iFncSendError(e.Message+"\n"+e.StackTrace);
}
}
}
// 2) Using Asynchronous Callback on a Socket
//(code can be structured better, this is only for testing purposes)
---------------------------------------------
private Socket iSocket;
private byte[] iBuffer = new byte[100000];
public void receiveStreamAsync()
{
iPacketsReceived = 0;
iReceivedPacketsLost = 0;
iReceivedPacketsLostPct = 0;
AsyncCallback AcceptReceive = new AsyncCallback(this.ReceiveData);
iSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any,iPort);
EndPoint tempRemoteEP = (EndPoint)RemoteIpEndPoint;
iSocket.Bind(RemoteIpEndPoint);
iSocket.BeginReceiveFrom(iBuffer, 0, iBuffer.Length,
SocketFlags.None, ref tempRemoteEP,AcceptReceive, null);
}
private void ReceiveData(IAsyncResult result)
{
try
{
AsyncCallback AcceptReceive = new AsyncCallback(this.ReceiveData);
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any,
iPort);
EndPoint tempRemoteEP = (EndPoint)RemoteIpEndPoint;
int numBytes = iSocket.EndReceiveFrom(result, ref tempRemoteEP);
long packetVolgnr = buildLong(iBuffer);
iPacketsReceived++;
iReceivedPacketSize = numBytes;
iReceivedPacketsLost = packetVolgnr - iPacketsReceived;
if (packetVolgnr != 0)
{
iReceivedPacketsLostPct =
Math.Round((double)iReceivedPacketsLost / (double)packetVolgnr *
100.0, 2);
}
iSocket.BeginReceiveFrom(iBuffer, 0, iBuffer.Length,
SocketFlags.None, ref tempRemoteEP, AcceptReceive, null);
}
catch (Exception e)
{
if ((iFncSendError != null) && (!iStop))
{
iFncSendError(e.Message + "\n" + e.StackTrace);
}
}
}
Emmanuel Lambert - 16 Apr 2004 18:33 GMT
Is there anybody out there who could help me or who has the slightest
idea what could be the source of this problem?
thanks a lot.
Emmanuel
Emmanuel Lambert - 19 Apr 2004 06:45 GMT
The problem got solved by increasing the receiver buffer size.
SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveBuffer, recbuffer);
At this moment, I get the impression UDP packets may be delivered with
duplicates in certain conditions. Is that correct?
Emmanuel
Tom Hall - 19 Apr 2004 17:05 GMT
I've been lurking because I didn't have a helpful response to your original
question, however....
Yes. Unreliable, duplicated and/or out of order packets or nothing at all.
Also as you found, the OS doesn't care if it loses some of the packets after
receiving them - I believe the backlog is only 8 packets but I don't
know/can't find where I read this.
Here's another gotcha - I can guarantee you will get packet loss about every
10 minutes or so if you constantly send. Windows XP etc, refreshes its ARP
cache (IP addess to MAC address lookup) every 10 minutes for used
destinations, 2 minutes for unused. If you are unlucky enough to send even
2 (yes TWO) UDP packets back to back while your system is waiting for the
ARP response, Windows will drop all packets except the first one. I have
been bitten by this "feature" - check out the docs here:
From
http://www.microsoft.com/windows2000/techinfo/howitworks/communications/networkb
asics/tcpip_implement.asp
"ARP queues only one outbound IP datagram for a specified destination
address while that IP address is being resolved to a media access control
address. If a User Datagram Protocol (UDP)-based application sends multiple
IP datagrams to a single destination address without any pauses between
them, some of the datagrams may be dropped if there is no ARP cache entry
already present."
The upshot is whether you don't use the connection much (and then send a
little burst of 2 or more packets) OR, you use continuously and send burst
of 2 or more packets in less time than the ARP response takes, some of them
WILL get lost forever!
Probably safest to assume some packets will always get lost and plan
accordingly.
On the other hand, with the exception of the ARP stuff above, on a fully
switched network pushing 200+ UDP packets/second - I have extremely low
(almost zero) packet loss!
Hope this helps
Tom
> The problem got solved by increasing the receiver buffer size.
> SetSocketOption(SocketOptionLevel.Socket,
[quoted text clipped - 4 lines]
>
> Emmanuel
Emmanuel Lambert - 20 Apr 2004 18:41 GMT
Tom, thanks a lot for your response. Very helpful information.
Emmanuel
Emmanuel Lambert - 20 Apr 2004 18:47 GMT
Tom
What I don't understand well is where the DUPLICATED packets come from
on a simple PC-to-PC connection with only a router in between. Which
element in this system may duplicate the packets and WHY? If they got
sent, they got sent and that's it. UDP is unreliable, so why would one
of these elements ever want to re-send packets?
thanks again for your response - much appreciated.
Emmanuel
Tom Hall - 20 Apr 2004 23:12 GMT
Duplicated packets typically only occur when you have multiple routes
between the two end points - like across the Internet. It would also be
possible for a switch to send a packet twice if it "thought" that its first
attempt had been aborted (ethernet collision).
Tom
> Tom
>
[quoted text clipped - 7 lines]
>
> Emmanuel