7

Recently, I started using the System.Net.Sockets class introduced in the Mango release of WP7 and have generally been enjoying it, but have noticed a disparity in the latency of transmitting data in debug mode vs. running normally on the phone.

I am writing a "remote control" app which transmits a single byte to a local server on my LAN via Wifi as the user taps a button in the app. Ergo, the perceived responsiveness/timeliness of the app is highly important for a good user experience.

With the phone connected to my PC via USB cable and running the app in debug mode, the TCP connection seems to transmit packets as quickly as the user taps buttons.

With the phone disconnected from the PC, the user can tap up to 7 buttons (and thus case 7 "send" commands with 1 byte payloads before all 7 bytes are sent.) If the user taps a button and waits a little between taps, there seems to be a latency of 1 second.

I've tried setting Socket.NoDelay to both True and False, and it seems to make no difference.

To see what was going on, I used a packet sniffer to see what the traffic looked like.

  • When the phone was connected via USB to the PC (which was using a Wifi connection), each individual byte was in its own packet being spaced ~200ms apart.

  • When the phone was operating on its own Wifi connection (disconnected from USB), the bytes still had their own packets, but they were all grouped together in bursts of 4 or 5 packets and each group was ~1000ms apart from the next.

btw, Ping times on my Wifi network to the server are a low 2ms as measured from my laptop.

I realize that buffering "sends" together probably allows the phone to save energy, but is there any way to disable this "delay"? The responsiveness of the app is more important than saving power.

Pretzel
  • 8,141
  • 16
  • 59
  • 84
  • Did you find a solution to this? Nagle algorithm sounds like the answer. I would be contacting Microsoft to find out why setting TCP_NODELAY doesn't disable Nagle on Windows Phone. Or, seeing if the workaround I posted flushes the TCP queue. Best regards, – Dr. Andrew Burnett-Thompson Jan 02 '12 at 22:11
  • I should add that I had mild success by turning off my Wifi radio and having the data go out over the cellphone's data connection, thru an open port on my firewall, to my TCP server. There was no send delay, but obviously this isn't a solution because it defeats the purpose of controlling something on your private LAN (not to mention leaving oneself open for attack.) – Pretzel Jan 03 '12 at 16:48

6 Answers6

2

This is an interesting question indeed! I'm going to throw my 2 cents in but please be advised, I'm not an expert on System.Net.Sockets on WP7.

Firstly, performance testing while in the debugger should be ignored. The reason for this is that the additional overhead of logging the stack trace always slows applications down, no matter the OS/language/IDE. Applications should be profiled for performance in release mode and disconnected from the debugger. In your case its actually slower disconnected! Ok so lets try to optimise that.

If you suspect that packets are being buffered (and this is a reasonable assumption), have you tried sending a larger packet? Try linearly increasing the packet size and measuring latency. Could you write a simple micro-profiler in code on the device ie: using DateTime.Now or Stopwatch class to log the latency vs. packet size. Plotting that graph might give you some good insight as to whether your theory is correct. If you find that 10 byte (or even 100byte) packets get sent instantly, then I'd suggest simply pushing more data per transmission. It's a lame hack I know, but if it aint broke ...

Finally you say you are using TCP. Can you try UDP instead? TCP is not designed for real-time communications, but rather accurate communications. UDP by contrast is not error checked, you can't guarantee delivery but you can expect faster (more lightweight, lower latency) performance from it. Networks such as Skype and online gaming are built on UDP not TCP. If you really need acknowledgement of receipt you could always build your own micro-protocol over UDP, using your own Cyclic Redundancy Check for error checking and Request/Response (acknowledgement) protocol.

Such protocols do exist, take a look at Reliable UDP discussed in this previous question. There is a Java based implementation of RUDP about but I'm sure some parts could be ported to C#. Of course the first step is to test if UDP actually helps!


Found this previous question which discusses the issue. Perhaps a Wp7 issue? Poor UDP performance with Windows Phone 7.1 (Mango)

Still would be interested to see if increasing packet size or switching to UDP works


ok so neither suggestion worked. I found this description of the Nagle algorithm which groups packets as you describe. Setting NoDelay is supposed to help but as you say, doesn't.

http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.nodelay.aspx

Also. See this previous question where Keepalive and NoDelay were set on/off to manually flush the queue. His evidence is anecdotal but worth a try. Can you give it a go and edit your question to post more up to date results?

Socket "Flush" by temporarily enabling NoDelay

Community
  • 1
  • 1
Dr. Andrew Burnett-Thompson
  • 20,980
  • 8
  • 88
  • 178
  • 1
    The debugger performance difference is good detail. Sending larger packets isn't a good solution to the problem of being buffered, adjusting buffer sizes would be better. – Shaun Wilson Dec 30 '11 at 00:40
  • While TCP isn't as good as UDP for 'twitch' games, I don't believe this is a twitch game, I also believe Pretzel wants reliable, ordered messages from the phone. Implementing (reliable,ordered) UDP sessions would require extra work prone to additional bugs and testing (for something TCP provides at the protocol level.) UDP favors applications which can tolerate data loss and continue functioning. I would urge against using UDP until you understand how to use an existing protocol effectively. – Shaun Wilson Dec 30 '11 at 00:51
  • The article posted for Poor UDP Performance is different in that it's due to too much data being sent too quickly through UDP. – Shaun Wilson Dec 30 '11 at 00:55
  • This is an interesting idea of adding more data to the transmission. You're right. It's a total hack. But it may get me the desired result. Since this is a "remote control" app (for controlling a media box), I imagine there are bytes that the server will just ignore. Let me give it a shot. – Pretzel Dec 30 '11 at 05:31
  • Yes, UDP is out of the question. The service I'm connecting to is explicitly TCP. Since the commands coming from the virtual remote are sent in a certain order, they should be received in the same order. – Pretzel Dec 30 '11 at 05:39
  • Ok, I tried the larger send size. 100 bytes instead of 1 byte. The commands still worked (as the server ignored the other 99 bytes which were all 0x00), but it made the WP7 app laggy. Because I was sending 100x the data I was previously sending, the asynchronous calls were taking longer to return and as such, button presses were backing up in the event queue. Too bad, too. I thought maybe you were on to something... – Pretzel Dec 30 '11 at 06:35
  • The original definition of hack by MIT was "an ingenious but unsightly solution to an impossible problem". No shame in it ;) Thanks for trying my suggestion. Another workaround is to keep 1 byte packets but introduce a null packet, so send your one command packet and then send null packets until the buffer is flushed and you receive an ack. I'll have a think about this but in the meantime good luck and hope you find the right solution! – Dr. Andrew Burnett-Thompson Dec 30 '11 at 09:35
  • Edited my answer describing the nagra algorithm which buffers packets in .net sockets and a possible workaround. – Dr. Andrew Burnett-Thompson Dec 30 '11 at 13:35
  • I had one other person try my test code and they did not experience the effect like I do, so this might be a hardware specific (or device driver) issue. You can download it at: rangerpretzel.com/wp7-tcp-test.zip – Pretzel Jan 03 '12 at 16:43
2

Andrew Burnett-Thompson here already mentioned it, but he also wrote that it didn't work for you. I do not understand and I do not see WHY. So, let me explain that issue:

Nagle's algorithm was introduced to avoid a scenario where many small packets had to been sent through a TCP network. Any current state-of-the-art TCP stack enables Nagle's algorithm by default!

Because: TCP itself adds a substantial amount of overhead to any the data transfer stuff that is passing through an IP connection. And applications usually do not care much about sending their data in an optimized fashion over those TCP connections. So, after all that Nagle algorithm that is working inside of the TCP stack of the OS does a very, very good job.

A better explanation of Nagle's algorithm and its background can be found on Wikipedia.

So, your first try: disable Nagle's algorithm on your TCP connection, by setting option TCP_NODELAY on the socket. Did that already resolve your issue? Do you see any difference at all?

If not so, then give me a sign, and we will dig further into the details.

But please, look twice for those differences: check the details. Maybe after all you will get an understanding of how things in your OS's TCP/IP-Stack actually work.

Frunsi
  • 7,099
  • 5
  • 36
  • 42
  • Already tried TCP_NODELAY -- had no effect. I have created a test suite so that other people (with unlocked WP7 devices) can try it. I had one other person try it and they do not experience the effect like I do, so this might be a hardware specific (or device driver) issue. You can download it at: rangerpretzel.com/wp7-tcp-test.zip – Pretzel Jan 03 '12 at 16:38
1

Most likely it is not a software issue. If the phone is using WiFi, the delay could be upwards of 70ms (depending on where the server is, how much bandwidth it has, how busy it is, interference to the AP, and distance from the AP), but most of the delay is just the WiFi. Using GMS, CDMA, LTE or whatever technology the phone is using for cellular data is even slower. I wouldn't imagine you'd get much lower than 110ms on a cellular device unless you stood underneath a cell tower.

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • I guess I should have been said in the OP that this is connecting to a Local server on my LAN via Wifi. I have tried the same code on a laptop connecting to the LAN over Wifi and it is snappy. But with the phone, it is slow. (same Wifi connection.) What I find so curious is that when the Phone is connected to my PC via USB (and running in debug mode), the phone is very snappy. Perhaps it is not using the phone's Wifi connection, but using the PC's network connection instead? – Pretzel Dec 23 '11 at 21:55
  • When connected via USB, the device will use a NAT IP provided by the USB connection, thus using the computers IP Address. – Erik Philips Dec 23 '11 at 21:57
  • Okay, that confirms part of the issue. The PC that I'm testing this on right now is a laptop and is also connecting to the LAN via Wifi. I don't think the issue is the latency of Wifi (ping times are 2ms.) – Pretzel Dec 23 '11 at 22:09
  • Then this is a VERY interesting question! (Sorry I don't have anything else to provide) – Erik Philips Dec 23 '11 at 22:11
  • Well, I appreciate the help... :) – Pretzel Dec 23 '11 at 22:17
1

Sounds like your reads/writes are buffered. You may try setting the NoDelay property on the Socket to true, you may consider trimming the Send and Receive buffer sizes as well. The reduced responsiveness may be a by-product of there not being enough wifi traffic, i'm not sure if adjusting MTU is an option, but reducing MTU may improve response times.

All of these are only options for a low-bandwidth solution, if you intend to shovel megabytes of data in either direction you will want larger buffers over wifi, large enough to compensate for transmit latency, typically in the range of 32K-256K.

    var socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
    {
        NoDelay = true,
        SendBufferSize = 3,
        ReceiveBufferSize = 3,                
    };

I didn't test this, but you get the idea.

Shaun Wilson
  • 8,727
  • 3
  • 50
  • 48
  • I tried adjusting the send and receive buffers down to 2 bytes, but it appeared to make no difference. I've done most of my testing with NoDelay = True, but I've also tried it with it set to False as well. Either way, it has had no effect. :( – Pretzel Dec 30 '11 at 06:36
  • Some more properties to try. Start experimenting, by playing with all these and recording results you can start to understand what the heck MS did when implementing sockets! http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.receivebuffersize.aspx – Dr. Andrew Burnett-Thompson Dec 30 '11 at 09:58
1

Have you tried setting SendBufferSize = 0? In the 'C', you can disable winsock buffering by setting SO_SNDBUF to 0, and I'm guessing SendBufferSize means the same in C#

rsaxvc
  • 1,675
  • 13
  • 20
0

Were you using Lumia 610 and mikrotik accesspoint by any chance?

I have experienced this problem, it made Lumia 610 turn off wifi radio as soon as last connection was closed. This added perceivable delay, compared to Lumia 800 for example. All connections were affected - simply switching wifi off made all apps faster. My admin says it was some feature mikrotiks were not supporting at the time combined with WMM settings. Strangely, most other phones were managing just fine, so we blamed cheapness of the 610 at the beginning.

If you still can replicate the problem, I suggest trying following:

  • open another connection in the background and ping it all the time.
  • use 3g/gprs instead of wifi (requires exposing your server to the internet)
  • use different (or upgraded) phone
  • use different (or upgraded) AP
Agent_L
  • 4,960
  • 28
  • 30
  • 1
    No, I was not. I was using an HTC Arrive (WP7). I gave up on this project and never figured out the answer. Sorry. :( – Pretzel Jan 14 '13 at 19:29
  • 1
    You're welcome. Btw, I should mention that I do recall using the phone's Internet connection (turned off the Wifi) and went out over the internet and came in thru an open port in my Firewall and the latency delay disappeared. So I think it may have been an issue with my phone's WiFi chip and/or the way the firmware was programmed. I sent my test code to another friend who had a different WP7 phone and he had no latency issues. *shrugs* – Pretzel Jan 16 '13 at 15:56
  • Perfectly consistent with my experiences : ) – Agent_L Jan 17 '13 at 15:19