最近,我开始使用WP7芒果版本中引入的System.Net.Sockets类,并且总体上很喜欢它,但是我注意到在调试模式下传输数据的延迟与在手机上正常运行时的延迟存在差异。
我正在编写一个"远程控制"应用程序,当用户点击应用程序中的按钮时,它会通过Wifi向LAN上的本地服务器传输单个字节。因此,应用程序的感知响应性/及时性对于良好的用户体验非常重要。
将手机通过USB线连接到我的电脑上,并在调试模式下运行应用程序,TCP连接传输数据包的速度似乎和用户点击按钮一样快。
在手机与PC断开连接的情况下,用户可以点击多达7个按钮(因此,在所有7个字节发送之前,7个"发送"命令具有1字节的有效载荷。)如果用户点击按钮并在点击之间等待一会儿,则似乎有1秒的延迟。
我已经尝试设置套接字。
为了了解发生了什么,我使用数据包嗅探器来查看流量的样子。
-
当手机通过USB连接到PC(使用Wifi连接)时,每个字节都在自己的数据包中,间隔约200ms。
-
当手机在自己的Wifi连接上运行时(与USB断开),字节仍然有自己的数据包,但它们都以4或5个数据包的形式分组在一起,每组间隔约1000ms。
顺便说一句,从我的笔记本电脑上测量到,我的Wifi网络到服务器的Ping时间很低,只有2毫秒。
我意识到缓冲"发送"在一起可能允许手机节省能源,但是有任何方法来禁用这种"延迟"?应用程序的响应性比省电更重要。
这确实是一个有趣的问题!我将投入我的2美分,但请注意,我不是System.Net.Sockets在WP7上的专家。
首先,在调试器中应该忽略性能测试。这样做的原因是,记录堆栈跟踪的额外开销总是会减慢应用程序的速度,无论操作系统/语言/IDE如何。应用程序应该在发布模式下进行性能分析,并与调试器断开连接。在你的情况下,它实际上更慢的断开!好的,我们来优化一下。
如果您怀疑数据包正在被缓冲(这是一个合理的假设),您是否尝试过发送更大的数据包?尝试线性增加数据包大小并测量延迟。你能在设备上用代码写一个简单的微分析器吗?例如:使用DateTime。Now或Stopwatch类记录延迟与数据包大小的关系。绘制这个图表可能会让你对你的理论是否正确有一些很好的了解。如果您发现立即发送了10字节(甚至100字节)的数据包,那么我建议每次传输只需推送更多数据。这是一个蹩脚的黑客,我知道,但如果它没有坏…
最后你说你正在使用TCP。你可以尝试UDP代替吗?TCP不是为实时通信而设计的,而是为精确通信而设计的。相比之下,UDP不检查错误,你不能保证交付,但你可以期待更快(更轻量,更低延迟)的性能。Skype和在线游戏等网络是建立在UDP之上的,而不是TCP。如果你真的需要接收确认,你可以在UDP上建立你自己的微协议,使用你自己的循环冗余检查错误检查和请求/响应(确认)协议。
这样的协议确实存在,看看在前面的问题中讨论的可靠UDP。有一个基于Java的RUDP实现,但我相信有些部分可以移植到c#上。当然,第一步是测试UDP是否真的有帮助!
找到前面讨论这个问题的问题。也许是Wp7的问题?Windows Phone 7.1 (Mango) UDP性能差
仍然有兴趣看看是否增加数据包大小或切换到UDP工作
好,所以这两个建议都不起作用。我找到了内格尔算法的描述它像你描述的那样分组。设置NoDelay应该有帮助,但正如你所说,没有。
http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.nodelay.aspx。请参阅前面的问题,其中将Keepalive和NoDelay设置为开启/关闭以手动刷新队列。他的证据是道听途说,但值得一试。你能试一试并编辑你的问题以发布更多最新的结果吗?
套接字"Flush"暂时启用NoDelay
Andrew Burnett-Thompson在这里已经提到过,但他也写道这对你不起作用。我不明白,也不明白为什么。那么,让我来解释一下这个问题:
引入Nagle的算法是为了避免必须通过TCP网络发送许多小数据包的情况。任何当前最先进的TCP堆栈都默认启用内格尔算法!因为:TCP本身给通过IP连接的数据传输增加了大量的开销。应用程序通常不太关心如何通过这些TCP连接以优化的方式发送数据。所以,毕竟在操作系统的TCP栈内部工作的Nagle算法做得非常非常好。
关于Nagle算法及其背景的更好解释可以在维基百科上找到。
所以,你的第一个尝试:通过在套接字上设置TCP_NODELAY选项来禁用TCP连接上的Nagle算法。你的问题已经解决了吗?你觉得有什么不同吗?
如果没有,请给我一个提示,我们将进一步深入研究。
但是,请仔细检查这些差异:检查细节。也许你最终会了解操作系统的TCP/ip栈是如何工作的。
很可能不是软件问题。如果手机使用WiFi,延迟可能会超过70毫秒(取决于服务器的位置、带宽、繁忙程度、对AP的干扰以及与AP的距离),但大部分延迟都是WiFi造成的。使用GMS、CDMA、LTE或其他手机传输蜂窝数据的技术会更慢。除非你站在信号塔下面,否则我无法想象你在蜂窝设备上获得比110毫秒低得多的信号。
听起来你的读/写是缓冲的。您可以尝试将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,
};
我没有测试这个,但是你明白了。
是否尝试设置SendBufferSize = 0?在'C'中,您可以通过将SO_SNDBUF设置为0来禁用winsock缓冲,我猜SendBufferSize在c#中也意味着相同
您是否使用Lumia 610和microtik accesspoint ?
我遇到过这个问题,它使Lumia 610在最后一次连接关闭后立即关闭wifi广播。与Lumia 800相比,这增加了可感知的延迟。所有的连接都会受到影响——只要关掉wifi,所有的应用程序就会变得更快。我的管理员说,这是当时microtiks不支持的一些功能,再加上WMM设置。奇怪的是,大多数其他手机都运行得很好,所以我们一开始就归咎于610的便宜。
如果您仍然可以重复这个问题,我建议您尝试以下操作:
- 在后台打开另一个连接并一直ping它。
- 使用3g/gprs代替wifi(需要将您的服务器暴露在互联网上)
- 使用不同(或升级)的手机
- 使用不同的(或升级的)AP