如何加速缓慢/延迟的Windows Phone 7(WP7)TCP套接字传输?

7
最近,我开始使用在Mango版本的WP7中引入的System.Net.Sockets类,并且通常很喜欢它,但是注意到在调试模式下与正常运行时传输数据的延迟存在差异。
我正在编写一个“远程控制”应用程序,当用户在应用程序中点击按钮时,通过Wifi向本地服务器传输单个字节。因此,应用程序的感知响应速度对于良好的用户体验非常重要。
使用USB电缆将手机连接到我的PC并在调试模式下运行应用程序时,TCP连接似乎可以像用户点击按钮一样快速传输数据包。
当手机断开与PC的连接后,用户可以点击多达7个按钮(因此发送了7个带有1个字节有效负载的“send”命令),在所有7个字节被发送之前。如果用户在点击之间等待一会儿,则会出现1秒的延迟。
我尝试过将Socket.NoDelay设置为True和False,但似乎没有任何区别。
为了查看发生了什么,我使用了数据包嗅探器来查看流量情况。
当手机通过USB连接到PC(使用Wifi连接)时,每个单独的字节都在自己的数据包中,间隔约200ms。
当手机在其自己的Wifi连接上运行(与USB断开连接)时,字节仍然有自己的数据包,但它们都被分组在4或5个数据包的突发中,并且每个组与下一个组间隔约1000ms。
顺便说一句,从我的笔记本电脑测量得到,服务器在我的Wifi网络上的Ping时间为低延迟的2ms。
我意识到缓冲“发送”可能允许手机节省能源,但是否有办法禁用此“延迟”?应用程序的响应速度比节省电力更重要。

你找到解决方案了吗?Nagle算法听起来像是答案。我会联系微软,看看为什么在Windows Phone上设置TCP_NODELAY并不能禁用Nagle。或者,看看我发布的解决方法是否可以清空TCP队列。最好的问候。 - Dr. Andrew Burnett-Thompson
我应该补充说明一下,关闭我的Wifi收发器并通过手机数据连接将数据传输到防火墙上的开放端口,然后发送到我的TCP服务器,这样有些成功。没有发送延迟,但显然这不是一个解决方案,因为它违背了在您私人局域网上控制某些东西的目的(更不用说让自己暴露于攻击之中了)。 - Pretzel
6个回答

2
这确实是一个有趣的问题!我要发表一下我的看法,但请注意,我不是 WP7 上 System.Net.Sockets 方面的专家。
首先,在调试器中进行性能测试应该被忽略。原因是记录堆栈跟踪的额外开销总会减慢应用程序的速度,无论操作系统/语言/IDE如何。应该在发布模式下对应用程序进行性能分析,并断开与调试器的连接。在你的情况下,断开连接后速度更慢了!好吧,让我们尝试优化一下。
如果你怀疑数据包正在缓冲(这是一个合理的假设),你是否尝试发送更大的数据包?尝试线性增加数据包大小并测量延迟时间。你能否在设备上编写一个简单的微型分析器来记录延迟时间和数据包大小之间的关系,例如使用 DateTime.Now 或 Stopwatch 类。绘制该图表可能会为你提供一些有关你的理论是否正确的好见解。如果你发现 10 字节(甚至 100 字节)的数据包可以立即发送,那么我建议你只需在每次传输时推送更多的数据。我知道这是一个愚蠢的 hack,但如果它没有问题...
最终你说你正在使用TCP。你能试试UDP吗?TCP并不是为实时通信而设计的,而是为准确通信而设计的。相比之下,UDP没有错误检查,不能保证传递,但可以期望更快(更轻量级,延迟更低)的性能。像Skype和在线游戏这样的网络都建立在UDP上,而不是TCP。如果你真的需要收到确认,你可以在UDP上构建自己的微型协议,使用自己的循环冗余校验进行错误检查和请求/响应(确认)协议
这样的协议确实存在,请看可靠UDP这个先前的问题中讨论。有一个基于Java的RUDP实现,但我相信一些部分可以移植到C#。当然,第一步是测试UDP是否真的有用!
发现了这个之前讨论过此问题的问题。可能是Wp7的问题吗? Windows Phone 7.1 (Mango)中UDP性能差
仍然很想看看增加数据包大小或切换到UDP是否有效。
好的,所以两个建议都没起作用。我找到了这个描述 Nagle 算法的文章,它按照你所描述的方式对数据包进行分组。设置 NoDelay 应该有所帮助,但正如你所说的那样,并没有起到作用。

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

此外,参见先前的问题,其中Keepalive和NoDelay被设置为手动清除队列。他的证据是个人经历,但值得一试。你可以尝试一下并编辑你的问题以发布更多最新的结果吗? 通过暂时启用NoDelay来“刷新”套接字

1
调试器性能差异是一个很好的细节。发送更大的数据包并不是解决缓冲问题的好方法,调整缓冲区大小会更好。 - Shaun Wilson
发布的有关UDP性能差的文章与众不同,因为它是由于太多数据通过UDP被过快地发送所导致的。 - Shaun Wilson
这是一个有趣的想法,可以增加传输的数据量。你说得对,这完全是个hack。但它可能会让我得到期望的结果。由于这是一个“遥控器”应用程序(用于控制媒体盒),我想服务器会忽略一些字节。让我试试看。 - Pretzel
是的,UDP不在考虑范围内。我连接的服务明确使用TCP。由于来自虚拟遥控器的命令按特定顺序发送,因此它们应该按相同顺序接收。 - Pretzel
MIT对“hack”的最初定义是“对于一个不可能的问题,想出一个巧妙但不太美观的解决方案”。这并不可耻 ;) 感谢您尝试我的建议。另一种解决方法是保持1字节数据包,但引入一个空数据包,因此发送一个命令数据包,然后发送空数据包直到缓冲区被刷新并收到确认。我会考虑一下这个问题,同时祝你好运,希望你能找到正确的解决方案! - Dr. Andrew Burnett-Thompson
显示剩余4条评论

2

Andrew Burnett-Thompson已经提到过这一点,但他还写道,它对你没有起作用。我不明白,也看不到为什么。因此,让我解释一下这个问题:

Nagle算法是为了避免许多小分组必须通过TCP网络发送的情况而引入的。任何现代的TCP堆栈都默认启用Nagle算法!

原因在于:TCP本身会为通过IP连接传输的任何数据传输添加大量开销。而应用程序通常不太关心如何在这些TCP连接上以优化的方式发送其数据。因此,在操作系统的TCP堆栈内部工作的Nagle算法非常出色。

Nagle算法及其背景的更好解释可以在维基百科上找到。

因此,您的第一个尝试是:通过在套接字上设置选项TCP_NODELAY来禁用TCP连接上的Nagle算法。这是否已经解决了您的问题?您是否看到任何区别?

如果不是这样,请告诉我,我们将深入了解详细信息。

但请注意,仔细检查这些差异:检查细节。也许最终您会了解操作系统的TCP/IP堆栈中的事情是如何工作的。


已经尝试过TCP_NODELAY -- 没有效果。我创建了一个测试套件,以便其他人(拥有解锁的WP7设备)可以尝试它。我让另一个人尝试了一下,他们没有像我一样遇到这种情况,所以这可能是硬件特定的(或设备驱动程序)问题。您可以在rangerpretzel.com/wp7-tcp-test.zip上下载它。 - Pretzel

1

你尝试过将SendBufferSize设置为0吗?在'C'中,您可以通过将SO_SNDBUF设置为0来禁用winsock缓冲,我猜SendBufferSize在C#中的意思也是一样的。


我还没有将它设置为零。虽然我尝试了1,但没有效果。现在我会尝试0。 - Pretzel

1
很可能这不是一个软件问题。如果手机使用WiFi,延迟可能高达70毫秒(取决于服务器所在位置、带宽、繁忙程度、对接入点的干扰以及与接入点的距离),但大部分延迟只是由WiFi引起的。使用GMS、CDMA、LTE或其他移动数据技术的手机速度更慢。除非你站在一个基站下面,否则我不认为你能得到低于110毫秒的延迟。

我想我应该在原帖中说明这是通过Wifi连接到我的局域网上的本地服务器。我已经尝试在连接到Wifi的笔记本电脑上使用相同的代码,速度非常快。但是用手机却很慢(相同的Wifi连接)。我觉得很奇怪的是,当手机通过USB连接到我的PC上(并在调试模式下运行)时,手机非常快。也许它没有使用手机的Wifi连接,而是使用PC的网络连接? - Pretzel
当通过USB连接时,设备将使用由USB连接提供的NAT IP,从而使用计算机的IP地址。 - Erik Philips
好的,那证实了问题的一部分。我正在测试的这台电脑是一台笔记本电脑,也是通过Wifi连接到局域网的。我不认为问题在于Wifi的延迟(ping时间为2毫秒)。 - Pretzel
那么这是一个非常有趣的问题!(抱歉我没有其他提供的内容) - Erik Philips
好的,感谢帮助... :) - Pretzel

1

听起来你的读写是有缓存的。你可以尝试将Socket的NoDelay属性设置为true,你也可以考虑调整发送和接收缓冲区大小。响应速度降低可能是因为wifi流量不足造成的,我不确定是否可以调整MTU,但减小MTU可能会改善响应时间。

所有这些都只是低带宽解决方案的选项,如果你打算在任一方向上传输兆字节的数据,你需要更大的wifi缓冲区,足以弥补传输延迟,通常在32K-256K范围内。

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

我没有测试过这个,但你能理解我的意思。


我尝试将发送和接收缓冲区调整为2个字节,但似乎没有任何改变。我大部分的测试都是使用NoDelay = True进行的,但我也尝试过将其设置为False。无论哪种方式,都没有产生影响。:( - Pretzel
有一些其他的属性可以尝试。开始实验,通过玩弄所有这些并记录结果,您可以开始理解微软在实现套接字时所做的事情!http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.receivebuffersize.aspx - Dr. Andrew Burnett-Thompson

0

你有使用Lumia 610和mikrotik accesspoint的经验吗?

我曾遇到过这个问题,使Lumia 610在最后一个连接关闭后立即关闭wifi。与Lumia 800相比,它增加了可感知的延迟。所有连接都受到影响 - 简单地关闭wifi会使所有应用程序更快。我的管理员说它是一些mikrotiks当时不支持的特性与WMM设置的结合。奇怪的是,大多数其他手机处理得很好,因此我们一开始认为是610的廉价造成的问题。

如果您仍然能够复制该问题,我建议尝试以下操作:

  • 在后台打开另一个连接并始终ping它。
  • 改用3g / gprs而不是wifi(需要将服务器暴露给Internet)
  • 使用不同(或升级)的手机
  • 使用不同(或升级)的AP

1
不,我不是。我使用的是HTC Arrive(WP7)。我放弃了这个项目,从未找到答案。抱歉。:( - Pretzel
1
不用客气。顺便提一下,我记得我使用了手机的互联网连接(关闭了Wifi),通过防火墙中的一个开放端口出去并进来,延迟问题消失了。所以我认为可能是我的手机WiFi芯片和/或固件编程方式的问题。我将我的测试代码发送给另一个拥有不同WP7手机的朋友,他没有延迟问题。 耸肩 - Pretzel
完全符合我的经验 :) - Agent_L

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接