TCP选项之TCP_CORK和TCP_NODELAY

news/2024/7/9 17:44:41 标签: 网络, python, epoll

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

这两个选项是互斥的,打开或者关闭TCP的nagle算法,下面用场景来解释

典型的webserver向客户端的应答,应用层代码实现流程粗略来说,一般如下所示:

  if(条件1{

     buffer_last_modified填充协议内容“Last-Modified: Sat, 04 May 2012 05:28:58 GMT”;

     sendbuffer_last_modified);

  }

 

   if(条件2{

     buffer_expires填充协议内容“Expires: Mon, 14 Aug 2023 05:17:29 GMT”;

     sendbuffer_expires);

   }

 

   。。。

   if(条件N{

     buffer_N填充协议内容“。。。”;

     sendbuffer_N);

   }

 

对于这样的实现,当前的http应答在执行这段代码时,假设有M(M<=N)个条件都满足,那么会有连续的M个send调用,那是不是下层会依次向客户端发出M个TCP包呢?答案是否定的,包的数目在应用层是无法控制的,并且应用层也是不需要控制的。

我用下列四个假设场景来解释一下这个答案

由于TCP是流式的,对于TCP而言,每个TCP连接只有syn开始和fin结尾,中间发送的数据是没有边界的,多个连续的send所干的事情仅仅是:

假如socket的文件描述符被设置为阻塞方式,而且发送缓冲区还有足够空间容纳这个send所指示的应用层buffer的全部数据,那么把这些数据从应用层的buffer,拷贝到内核的发送缓冲区,然后返回。

 

假如socket的文件描述符被设置为阻塞方式,但是发送缓冲区没有足够空间容纳这个send所指示的应用层buffer的全部数据,那么能拷贝多少就拷贝多少,然后进程挂起,等到TCP对端的接收缓冲区有空余空间时,通过滑动窗口协议(ACK包的又一个作用----打开窗口)通知TCP本端:“亲,我已经做好准备,您现在可以继续向我发送X个字节的数据了”,然后本端的内核唤醒进程,继续向发送缓冲区拷贝剩余数据,并且内核向TCP对端发送TCP数据,如果send所指示的应用层buffer中的数据在本次仍然无法全部拷贝完,那么过程重复。。。直到所有数据全部拷贝完,返回。(send指定的buffer大小必须全部发送完,才会返回)

请注意,对于send的行为,我用了“拷贝一次”,send和下层是否发送数据包,没有任何关系。

 

假如socket的文件描述符被设置为非阻塞方式,而且发送缓冲区还有足够空间容纳这个send所指示的应用层buffer的全部数据,那么把这些数据从应用层的buffer,拷贝到内核的发送缓冲区,然后返回。

 

假如socket的文件描述符被设置为非阻塞方式,但是发送缓冲区没有足够空间容纳这个send所指示的应用层buffer的全部数据,那么能拷贝多少就拷贝多少,然后返回拷贝的字节数。多涉及一点,返回之后有两种处理方式:

1.死循环,一直调用send,持续测试,一直到结束(基本上不会这么搞)。

2.非阻塞搭配epoll或者select,用这两种东西来测试socket是否达到可发送的活跃状态,然后调用send(高性能服务器必需的处理方式)。

 

综上,以及请参考《TCP选项之SO_RCVBUF和SO_SNDBUF》,你会发现,在实际场景中,你能发出多少TCP包以及每个包承载多少数据,除了受到自身服务器配置和环境带宽影响,对端的接收状态也能影响你的发送状况。

 

至于为什么说“应用层也是不需要控制发送行为的”,这个说法的原因是:

软件系统分层处理、分模块处理各种软件行为,目的就是为了各司其职,分工。应用层只关心业务实现,控制业务。数据传输由专门的层面去处理,这样应用层开发的规模和复杂程度会大为降低,开发和维护成本也会相应降低。

 

再回到发送的话题上来:)之前说应用层无法精确控制和完全控制发送行为,那是不是就是不控制了?非也!虽然无法控制,但也要尽量控制!

如何尽量控制?现在引入本节主题----TCP_CORK和TCP_NODELAY。

cork:塞子,塞住

nodelay:不要延迟

 

TCP_CORK:尽量向发送缓冲区中攒数据,攒到多了再发送,这样网络的有效负载会升高。简单粗暴地解释一下这个有效负载的问题。假如每个包中只有一个字节的数据,为了发送这一个字节的数据,再给这一个字节外面包装一层厚厚的TCP包头,那网络上跑的几乎全是包头了,有效的数据只占其中很小的部分,很多访问量大的服务器,带宽可以很轻松的被这么耗尽。那么,为了让有效负载升高,我们可以通过这个选项指示TCP层,在发送的时候尽量多攒一些数据,把他们填充到一个TCP包中再发送出去。这个和提升发送效率是相互矛盾的,空间和时间总是一堆冤家!!

TCP_NODELAY:尽量不要等待,只要发送缓冲区中有数据,并且发送窗口是打开的,就尽量把数据发送到网络上去。

 

很明显,两个选项是互斥的。实际场景中该怎么选择这两个选项呢?再次举例说明

webserver,,下载服务器(ftp的发送文件服务器),需要带宽量比较大的服务器,用TCP_CORK。

涉及到交互的服务器,比如ftp的接收命令的服务器,必须使用TCP_NODELAY。默认是TCP_CORK。设想一下,用户每次敲几个字节的命令,而下层在攒这些数据,想等到数据量多了再发送,这样用户会等到发疯。这个糟糕的场景有个专门的行话来形容-----粘(nian拼音二声)包。

转载于:https://my.oschina.net/yangan/blog/185238


http://www.niftyadmin.cn/n/1681445.html

相关文章

android 基础培训ppt,Android基础之内部培训.ppt

Android基础之内部培训May 30, 2007 V2.0 Android Study Agenda Building Blocks Application Model UI IPC Security Q&A Building Blocks What an application would do Display UI Let user navigate from one UI to another Provide services Act due to cared events …

业界对生成图片缩略图的做法归纳

网站如果有很多用户上传图片(相册&#xff0c;商品图片)&#xff0c;一般的做法是将用户图片保存在磁盘上面(数据库中记录图片的地址)。用户上传的时候按照原图、中图、小图等各个尺寸都生成一份保存在磁盘上。比如php的网店系统echsop就是这么做的&#xff0c;而shopex之类也大…

android system app 权限修改,Android系统 给第三方应用(system/app) 权限开启(不会弹授予权限窗口)...

frameworks/base/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java类是对默认权限管理类可以查看grantDefaultSystemHandlerPermissions该方法&#xff0c;里面有就有授予权限类似方法,可以模仿我们可以通过此类来对我们系统中存在的应用进行默认权…

1375. 奶牛回家 (Dijkstra)

题目链接 晚餐时间马上就到了&#xff0c;奶牛们还在各自的牧场中悠闲的散着步。 当农夫约翰摇动铃铛&#xff0c;这些牛就要赶回牛棚去吃晚餐。 在吃晚餐之前&#xff0c;所有奶牛都在自己的牧场之中&#xff0c;有些牧场中可能没有奶牛。 每个牧场都通过一条条道路连接到…

android资料转移到iphone,怎么将安卓手机数据资料转到iPhone上

怎么将安卓手机数据资料转到iPhone上&#xff0c;下面我们来看看相关的教程&#xff1a;功能介绍iPhone6马上要上市了&#xff0c;怎么才能数据资料快速从旧手机换到新手机呢&#xff1f;现在&#xff0c;有了iTools强大的手机搬家功能&#xff0c;新旧设备间无缝衔接&#xff…

搜索与图论 ---- Bellmen-ford 算法求最短路 及 路径输出

Bellmen-ford 算法 进行 n-1 次循环&#xff0c;每次循环&#xff0c;枚举每条边&#xff0c;看是否可以更新当前的边&#xff08;三角不等式&#xff09; dist [ a ] min ( dist [ a ] ,dist [ b ] t ) 等同于 dist [ a ] < dist [ b ] t 备份数组 backup [ ] &#xf…

wamp server php环境绑定域名

思路&#xff1a; 用花生壳做动态域名解析用wamp server 在本机上做一个 php web server;这样就可以让一台内网电脑做一个测试用的服务器&#xff1b; 一&#xff1a;wamp server php环境绑定域名 安装wamp server 开启虚拟主机功能---点击wamp server图标--apache---httpd.con…

godaddy android 证书,java.security.cert.CertPathValidatorException:找不到证书路径的信任锚. Android 2.3...

在我的服务器(生产服务器)中,我有一个goDaddy ssl证书.我有iOS和Android应用程序连接服务器,iOS连接没有问题,Android与版本4. *一切都很好,但设备2.3.*我总是得到SSLHandshakeException.我已经在stackoverflow(here)中看到了类似的线程,但没有人帮忙.然后我看到this线程谈论扩…