0

I'm writing udp multicast datagrams receiver.

If I receive datagram with number X and datagram "X-1" still not received I should wait for 5 ms (because UDP doesn't garantee order of packets) and if datagram "X-1" still not received I should recover.

How to do that? I want to store for each received packet in array the "timestamp" when packet is received. later I want to compare current time with timestamp, and if difference is more than 5 ms and packet X-1 is missing I should recover.

Probably you can suggest another algorithm?

Or if mine is fine how can I convert "current time" to "int" or "long" milliseconds? I don't want to use DateTime.Now object because it contains a lot of garbage I don't need and I need to do this processing several thousands times per second.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Oleg Vazhnev
  • 23,239
  • 54
  • 171
  • 305
  • 1
    If you just need *relative time*, `Stopwatch` might be handy. Also, does `DateTime.Now` add *enough* overhead to affects performance/results? ("Several thousand times per second" is *much less* than the "billions of clock ticks per second" found on modern CPUs ;-) –  Mar 13 '12 at 18:55
  • 1
    Neither the delivery nor the order is guaranteed by UDP. If you send packet X right after X-1, there is no guarantee that X will reach the destination before X-1. – GETah Mar 13 '12 at 18:58
  • @GETah thanks I know how UDP works. `Stopwatch` might work but probably just storring `TickCount` is better... – Oleg Vazhnev Mar 13 '12 at 19:22

3 Answers3

8

DateTime.Now doesn't actually "contain a lot of garbage" - it's a value type which just wraps a ulong. I would actually suggest that you use a Stopwatch though, as that's a more appropriate type for measuring differences in time. (As noted in comments, the actual accuracy of DateTime.Now is too low for you anyway.)

I'd personally recommend creating one stopwatch for each of these that you require, but you could use just a single one. (Hint: allocating "several thousand" objects per second is not a problem for .NET... prove that the simplest solution is too slow before you move to something more complicated.)

Of course, Stopwatch deals with measuring time rather than waiting for time. It's not clear what you mean by "recover" in this situation though - do you definitely need to take some action at that point, or can you just wait until the next datagram comes in? If at all possible, I'd make the code reactive, doing "the right thing" when each packet arrives, using a stopwatch for timing the difference between one packet and the next if that's necessary.

For testing purposes you may well want to wrap the stopwatch in an interface so that you can inject a test double.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • What about the handling/differences of `Stopwatch` and/or `DateTime.Now` over (rare but possible) clock adjusts? –  Mar 13 '12 at 19:00
  • To clarify, the DateTime class has a maximum precision of ~15 ms due to thread context switching, which makes it unsuitable for performance analysis. Definitely 2nd the recommendation to use the Stopwatch class, which uses the Windows performance counter APIs for a much greater precision. – Chris Mar 13 '12 at 19:00
  • @Chris Lame, I always thought it was "high precision" :( Supporting article (note precision vs. accuracy): http://blogs.msdn.com/b/ericlippert/archive/2010/04/08/precision-and-accuracy-of-datetime.aspx –  Mar 13 '12 at 19:01
  • 1
    @Chris: No, DateTime (which is a struct, not a class) has a very fine *precision*, but DateTime.Now has relatively low *accuracy*. See http://blogs.msdn.com/b/ericlippert/archive/2010/04/08/precision-and-accuracy-of-datetime.aspx – Jon Skeet Mar 13 '12 at 19:02
  • 1
    Right, accuracy vs precision, thanks for the correction. The overall point is that if you're trying to get 1ms level accuracy from DateTime.Now, you're going to have issues. – Chris Mar 13 '12 at 19:04
  • @digEmAll: It appears to use ticks internally which is a `ulong`, but only appears to hold values that are also valid for `long` (`MaxTicks` uses 62 bits) – Guvante Mar 13 '12 at 19:19
  • The first line says "it's a value type which just wraps a double", that's a bit misleading imo. As far as I know DateTime wraps an ulong... (sorry @Guvante I removed my previous comment) – digEmAll Mar 13 '12 at 19:20
  • launching `Stopwatch` for every single packet I receive from network even taking into account that .NET can process thousands of them easily... I'm not sure it's a best solution.... Probably `Environment.TickCount` approach will be 1000 times faster and even more easy? I understand that overoptimization is bad but I also don't want to make my application 1000 times slower at every single point of execution without reason because 1000 * 1000 * 1000 = a lot of time – Oleg Vazhnev Mar 13 '12 at 19:32
  • udp multicast is used to receive market data from stocks exchange, even 0.1 ms save is pretty important... Also I don't need to catch exact 5 ms difference. It's ok for me to start recover somewhere between 5ms and 10ms after packet is missed – Oleg Vazhnev Mar 13 '12 at 19:37
  • @javapowered: You're "not sure it's a best solution" or you've *measured it and validated your assumptions*. Oh, and `Environment.TickCount` won't give you the resolution you want either. Really: until you've measured the most elegant solution you will have *no idea* whether it's too expensive or not. I've just done a quick microbenchmark (which I still wouldn't take as representative, but it's better than nothing) which started over 16 million stopwatches per second on average, over a period of ten seconds. – Jon Skeet Mar 13 '12 at 19:38
  • @JonSkeet thanks Jon. while working how much resources `Stopwatch` occupies? because I'm thinking about `Stopwatch` as about something that "ticks", like clocks they need energy (processor power) to "tick" or `Stopwatch` more like "just store when I was started" and nothing else? – Oleg Vazhnev Mar 13 '12 at 19:44
  • @javapowered: It's just a "store the underlying timer's count when I was started" but using a timer with a higher frequency than `DateTime.Now` does. – Jon Skeet Mar 13 '12 at 19:46
  • Um, you can start ONE stopwatch and just ask it for elapsed milliseconds like you would recording DateTime.Now, then later, ask it for elapsed milliseconds again and calculate the difference. You don't need a stopwatch instance for each packet. Think of the stopwatch instance as a high accuracy / high precision timer. And for the record, you don't have to STOP the stopwatch to get the elapsed milliseconds.. you can let it keep running indefinitely. – Chris Mar 14 '12 at 00:28
  • @Chris: I know (hence the "you could use a single one"), but I think it's cleaner not to have to store the previous value. It feels more *logical* to me. If it became a performance issue, I'd change - but I'd go with the way I felt was more logical first. – Jon Skeet Mar 14 '12 at 06:23
  • @Jon, based on his original question, he wants to store a 'timestamp' when a packet is received. Later, he wants to compare that with the current 'timestamp' to determine if 5ms have elapsed. Based on the original intent, he's wanting to store the timestamp with the packet anyway, which then gets compared to the current value, so I see absolutely zero issues with keeping a single running stopwatch instance and simply grabbing the current 'timestamp' from there. – Chris Mar 14 '12 at 18:20
  • @Chris: I suspect it would work, yes. It just doesn't feel as logical to me - which I would certainly concede is a personal opinion - and the argument of "it means allocating a few thousand more objects per second" isn't a good enough one to influence the decision. If the OP finds your way of thinking about it more logical, that's absolutely fine. – Jon Skeet Mar 14 '12 at 18:25
2

Socket(or udpClient.Client) has a property ReceiveTimeout you can use it. DateTime has also DateTime.Now.Ticks which can be used as timestamps( or a static long as a sequence counter).

L.B
  • 114,136
  • 19
  • 178
  • 224
0

Environment.TickCount is the fastest call if I remember correctly, but might produce the largest number of problems - it is an integer (32 bit) number of milliseconds since machine restart. It will overflow every few months, so make sure when you calculate the difference, you allow for the number to be negative and take that into account.

See http://msdn.microsoft.com/en-us/library/system.environment.tickcount.aspx for detailed description.

Thist post has a good description of each method, precision, and which WinAPI they call

Community
  • 1
  • 1
Yuri Astrakhan
  • 8,808
  • 6
  • 63
  • 97