TCP协议下Socket接收比较慢点原因

在做一个游戏,发现阻塞和异步方式接受服务端的包都很反应很慢(不是网速问题),本机访问本机没这个问题,局域网有感觉200ms左右的延迟,部分机型感觉明显,部分不明显。找了很多资料,查到下面的文章,总算明白了。

https://support.microsoft.com/zh-cn/kb/214397

设计问题-通过使用 Winsock TCP 发送较小的数据段

 电子邮件

 打印

重要说明:本文是由 Microsoft 机器翻译软件进行的翻译并可能由 Microsoft 社区通过社区翻译机构(CTF)技术进行后期编辑,或可能是由人工进行的翻译。Microsoft 同时向您提供机器翻译、人工翻译及社区后期编辑的文章,以便对我们知识库中的所有文章以多种语言提供访问。翻译的文章可能存在词汇、句法和/或语法方面的错误。Microsoft 对由于内容的误译或客户对内容的使用所导致的任何不准确、错误或损失不承担责任。

点击这里察看该文章的英文版: 214397

概要

您需要通过 TCP 发送较小的数据的数据包,Winsock 应用程序设计时尤其重要。不会不考虑到延迟的确认,Nagle 算法以及 Winsock 缓冲的交互设计可以显著影响性能。本文讨论了这些问题,使用了几个案例研究,并派生一连串 Winsock 应用程序从高效地发送较小的数据的数据包的建议。

更多信息

背景

当 Microsoft TCP 堆栈接收数据包时,200 毫秒延迟计时器响起。当最终发送一个 ACK 时,延迟计时器重置,并且接收到下一个数据包时,将启动另一个 200 毫秒延迟。为了提高在互联网和内联网应用程序的效率,Microsoft TCP 堆栈使用以下标准来决定什么时候发送一个 ACK 数据包接收到的数据 ︰

如果延迟计时器过期之前收到第二个数据包,将确认发送。

如果有数据要发送 ACK 的方向相同,收到第二个数据包,并延迟计时器过期之前,确认是 piggybacked 与数据段并立即发送。

当延迟计时器到期时,将确认发送。

若要避免 congest 网络的小型数据包,Microsoft TCP 堆栈通过 Nagle 算法默认情况下,将合并来自多个发送呼叫和延迟直到上一个数据包的 ACK 发送接收从远程主机发送的较小的数据缓冲区。Nagle 算法的两个例外情况如下 ︰

如果堆栈已合并数据的缓冲区最大传输单位 (MTU) 比更大,大的数据包而无需等待来自远程主机的确认立即发送。在以太网上,tcp/ip 的 MTU 为 1460 字节。

应用 TCP_NODELAY 套接字选项,以禁用 Nagle 算法,以使较小的数据的数据包会传输到远程的主机,而不会延迟。

为了优化性能,在应用层,Winsock 副本从应用程序的数据缓冲区发送到 Winsock 内核缓冲区调用。然后,堆栈使用自己 (如 Nagle 算法) 的试探法确定何时把数据包在网络上。您可以更改的 Winsock 内核缓冲分配到套接字使用 SO_SNDBUF 选项 (它是 8k,默认情况下)。如有必要,多 SO_SNDBUF 缓冲区大小 Winsock 可以极大地缓冲。在大多数情况下,在应用程序完成发送只表示应用程序中的数据缓冲区发送调用复制到 Winsock 内核缓冲区,并不表示数据已达到网络媒体。唯一的例外是当您禁用了 Winsock 缓冲通过将 SO_SNDBUF 设置为 0。

Winsock 使用下列规则来指示完成发送给应用程序 (具体取决于调用发送方式,完成通知可能会返回一个阻塞调用,发送信号事件或调用通知函数,该函数等) ︰

如果套接字仍然位于 SO_SNDBUF 配额,Winsock 拷贝数据从应用程序发送并指示完成发送给应用程序。

如果套接字已 SO_SNDBUF 配额之外,没有堆栈内核缓冲区中仍然只有一个以前缓冲的发送,Winsock 拷贝数据从应用程序发送并指示完成发送给应用程序。

如果套接字是 SO_SNDBUF 配额之外,还有多个以前缓冲中的堆栈内核缓冲区发送 Winsock 会复制从应用程序发送的数据。直到堆栈完成足够发送放回 SO_SNDBUF 配额或只有一个未完成发送条件内的套接字,Winsock 并不表示完成发送给应用程序。

案例研究 1

概述 ︰

Winsock TCP 客户端需要将 10000 记录发送到 Winsock TCP 服务器,存储在数据库中。记录的大小因 100 字节长到 20 个字节。为了简化应用程序逻辑,设计,情况如下 ︰

客户端没有阻止发送只。该服务器将执行仅阻止接收。

客户端套接字将 SO_SNDBUF 设置为 0,这样单个数据段中发出的每个记录。

服务器在循环中调用接收。发布在接收缓冲区是 200 个字节,因此可能收到一个接收调用中的每个记录。

性能 ︰

在测试期间,开发人员查找客户端可以只发送到服务器的每秒五条记录。总 10000 记录最大值在 976 64k 字节的数据 (10000 * 100 / 1024年),花费超过半个小时将发送到服务器。

分析 ︰

由于客户端不会设置 TCP_NODELAY 选项,Nagle 算法强制 TCP 堆栈来等待一个 ACK 之前可以将另一个数据包发送线路上。但是,客户端已禁用通过 SO_SNDBUF 选项设置为 0 的 Winsock 缓冲。因此,10000 发送调用必须发送和确认分别。每个 ACK 是延迟的 200 毫秒,因为服务器的 TCP 堆栈上发生以下情况 ︰

当服务器收到一个数据包时,其 200 毫秒延迟计时器响起。

服务器不需要发送任何内容,因此不能 piggybacked ACK。

客户端将不会发送另一个数据包,除非得到确认前一个包。

在服务器上的延迟计时器过期并将确认发送回。

如何改进 ︰

有此设计两个方面的问题。首先,没有延迟计时器问题。客户端需要能够到 200 毫秒内服务器发送两个数据包,因为默认情况下,客户端使用 Nagle 算法,应该只需使用默认 Winsock 缓冲,并将 SO_SNDBUF 设置为 0。一旦 TCP 堆栈已合并比最大传输单位 (MTU) 更大的缓冲区,一个全尺寸的数据包被发送立即而无需等待来自远程主机的确认。

其次,这种设计为每个记录的这种小尺寸调用一个发送。发送此大小的小不是非常有效的。在这种情况下,开发人员可能需要填充到 100 个字节的每个记录并发送 80 记录从一个客户端一次发送呼叫。要让服务器知道将总共发送多少条记录,客户端可能想要从沟通开始修复大标头包含要执行的记录数。

案例研究 2

概述 ︰

Winsock TCP 客户端应用程序打开的 Winsock TCP 服务器应用程序提供股票报价服务的两个连接。第一个连接用作命令通道将股票代码发送到服务器。第二个连接作为数据信道用于接收股票报价。在建立两个连接之后,客户端向服务器通过命令通道发送股票代码和等待股价要回来通过数据通道。只在收到第一个股票报价之后,它会向服务器发送下来,股票代码。在客户端和服务器未设置 SO_SNDBUF 和 TCP_NODELAY 选项。

性能 ︰

在测试期间,开发人员查找客户端仅能获得每秒五个报价。

分析 ︰

这种设计一次只允许一个出色的股票报价请求。第一个股票发送通过命令通道 (连接) 到服务器,并且响应立即重新从服务器发送到客户端通过数据通道 (连接)。然后,客户端立即发送第二个股票代码请求中发送呼叫请求缓冲区复制到 Winsock 内核缓冲区发送立即返回。但是,客户端的 TCP 堆栈不能发送请求从其内核缓冲区立即因为第一个通过发送命令通道未尚未确认。200 毫秒延迟计时器在后服务器命令通道过期,则第一个符号请求的确认会回到客户端。然后,第二个报价请求已成功发送到服务器 200 女士为第二个股票报价恢复后立即通过数据通道因为到目前为止,在客户端数据信道延迟计时器已过期的延迟之后。服务器收到前一报价响应确认。(请记住,客户端无法发送 200 毫秒,第二个股票报价请求这样为延迟计时器过期并向服务器发送一个 ACK 客户端上显示时间)。因此,客户端获取的第二个报价响应并且可以发布另一个报价请求,遵守相同的周期。

如何改进 ︰

两个连接 (通道) 设计在此处是不必要的。如果只有一个连接用于股票报价请求和响应,可以引述响应 piggybacked 报价请求的确认,并立即回来。为了进一步提高性能,客户端可以”多路传输”股票报价的多个请求到一个发送呼叫的服务器和服务器可能还”多路传输”多个报价响应到客户端一次发送调用。如果由于某种原因确实需要两个单向通道设计,双方应设置 TCP_NODELAY 选项,以便无需等待前一个数据包的 ACK,可以立即发送小数据包。

建议 ︰

而在编造这些两个案例研究,它们有助于阐明某些最坏的情况。在设计应用程序,其中涉及到大量的小型数据段发送和 recvs,应考虑以下准则 ︰

如果的数据段不急于,应用程序应合并它们到更大的数据块要传递到发送调用。因为可能会被复制到 Winsock 内核缓冲区发送缓冲区,该缓冲区不应太大。略少于 8k 时通常是有效。只要 Winsock 内核获取比 MTU 大块,它会发送出多个大包和剩余的最后一个数据包。除的最后一个数据包的发送端不会命中 200 毫秒延迟计时器。最后一个数据包,它正好是一个奇数据包中,仍可能会有延迟的确认算法。如果发送端堆栈获取 MTU 大于另一个块,它仍然可以绕过 Nagle 算法。

如果可能,请避免使用单向数据流的套接字连接。通过单向套接字的通信,这是更容易受到 Nagle 和延迟确认算法。如果通信遵循请求和响应流,则应使用单个插座进行发送和 recvs,以便可以在响应 piggybacked ACK。

如果要立即发送所有较小的数据段,设置在发送端的 TCP_NODELAY 选项。

要保证网络上发送一个数据包,当发送完成由 Winsock,除非您不应该 SO_SNDBUF 设置为零。实际上,默认 8k 缓冲区已试探性地确定适用于大多数情况下,您不能更改它除非进行了测试,新的 Winsock 缓冲区设置使您可以更好的性能,而不是默认。此外,将 SO_SNDBUF 设置为零很是有用的应用程序执行批量数据传输的。甚至,实现最大效率使用时应结合双缓冲 (在任意给定时间多个未完成发送) 然后重叠 I/O。

如果不需要保证数据传递,使用 UDP。

参考

有关延迟确认和 Nagle 算法的详细信息,请参阅 ︰

Braden,R.[1989],RFC 1122,要求互联网主机的通讯层,互联网工程任务组。

警告:本文已自动翻译

属性

文章 ID:214397 - 上次审阅时间:03/14/2015 10:13:00 - 修订版本: 4.0

关键字:

kbdswnet2003swept kbapi kbinfo kbip kbnetwork kbwinsock kbmt KB214397 KbMtzh

时间: 2024-08-09 06:48:15

TCP协议下Socket接收比较慢点原因的相关文章

网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程

Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服务器进程B1同时为客户进程A1.A2和B2提供服务. Socket概述 ①   所谓Socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄.应用程序通常通过“套接字”向网络发出请求或者应答网络请求. ②   Socket是连接运行在网络上的两个程序间的双向通信的端点. ③  

Android基础入门教程——7.6.3 基于TCP协议的Socket通信(2)

Android基础入门教程--7.6.3 基于TCP协议的Socket通信(2) 标签(空格分隔): Android基础入门教程 本节引言: 上节中我们给大家接触了Socket的一些基本概念以及使用方法,然后写了一个小猪简易聊天室的 Demo,相信大家对Socket有了初步的掌握,本节我们来学习下使用Socket来实现大文件的断点续传! 这里讲解的是别人写好的一个Socket上传大文件的例子,不要求我们自己可以写出来,需要的时候会用 就好! 1.运行效果图: 1.先把我们编写好的Socket服务

基于TCP协议的socket套接字编程

基于TCP协议的socket套接字编程 一.什么是Socket Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议. 所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的. [ 注意:也有

TCP协议下的粘包问题

TCP协议下的粘包问题 粘包问题出现在TCP协议下,在UDP协议下不会出现粘包的问题. 粘包问题出现的原因: 应用层被成为应用元,操作系统被被称为系统元 合包机制:在TCP协议下有一个合包机制,当应用层传输过来数据后,如果数据较小,并且连续多次传输,此时nagle算法会对把多个数据进行 打包,统一发送给接收方, 好处是:减少了网络资源的消耗,接收方只需要给发送方回传一份回执即可,如果不进行合包操作,每发送一条数据,接收方就需要回一份回执,会大量消耗网络资源. 弊端是:由于TCP协议下字节流没有明

于TCP协议的socket通信

基于TCP协议Socket服务端和客户端的通信模型: Socket通信步骤: 1.建立服务端ServerSocket和客户端Socket 2.打开连接到Socket的输出输入流 3.按照协议进行读写操作 4.关闭相对应的资源 多线程服务器 多线程用来实现 服务器与多客户端之间的通信 基本步骤 1 服务器创建serverSocket,循环调用accept()等待客户端连接 2 客户端创建一个scoket并请求和服务器端连接 3 服务器端接收客户端请求,创建socket与该客户建立专线连接 4 建立

Android基础入门教程——7.6.2 基于TCP协议的Socket通信(1)

Android基础入门教程--7.6.2 基于TCP协议的Socket通信(1) 标签(空格分隔): Android基础入门教程 本节引言: 上一节的概念课枯燥无味是吧,不过总有点收获是吧,本节开始我们来研究基于TCP协议的Socket 通信,先来了解下Socket的概念,以及Socket通信的模型,实现Socket的步骤,以及作为Socket服务 端与客户端的两位各做要做什么事情!好的,我们由浅入深来扣这个Socket吧! 1.什么是Socket? 2.Socket通信模型: Socket通信

网络编程(二)——TCP协议、socket

TCP协议与socket套接字 一.TCP协议 1.可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会超过IP数据包的长度,以确保单个TCP数据包不必再分割. 2.(1)三次握手建链接(2)四次挥手断开链接(3)tcp协议的状态(4)syn洪水攻击与半连接池 3.(1)三次握手建立链接.四次挥手断开链接(各种状态) (2)syn洪水攻击与半连接池 syn洪水攻击:就是让服务器资源耗尽,无法提供正常的服务,间接地拒绝 半连接池:暂时存放请求,用

Python网络编程02/基于TCP协议的socket简单的通信

目录 Python网络编程02/基于TCP协议的socket简单的通信 1.昨日内容回顾 2.socket 2.1 socket套接字 2.2 基于TCP协议的socket简单通信 Python网络编程02/基于TCP协议的socket简单的通信 1.昨日内容回顾 1.单播:单独联系某一个人 2.广播:给所有人发送消息(群发) 3.比特流:bit就是0101跟水流一样的源源不断的发送01010101 4.以太网协议:将数据进行分组:一组称之为一帧,数据报 head|data head:18字节:

TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q

TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q 一.TCP协议下的服务端并发 ''' 将不同的功能尽量拆分成不同的函数,拆分出来的功能可以被多个地方使用 TCP服务端实现并发 1.将连接循环和通信循环拆分成不同的函数 2.将通信循环做成多线程 ''' # 服务端 import socket from threading import Thread ''' 服务端 要有固定的IP和PORT 24小时不间断提供服务 能够支持并发 ''' server = sock