选项TCP_NODELAY是禁用Nagle算法,即数据包立即发送出去,而选项

上右图显示的选项TCP_CORK的理论情况,但是在各个具体协议栈的实际实现中,有一些机制会打破选项TCP_CORK的这个“完全”堵塞(即数据包长度不到一个MSS则不允许发送)特性。以linux

3.4.4版本的内核代码实现为例,正常的tcp数据发送流程为(调用片段:仅从tcp层往ip层发送的函数调用关系):

tcp_push() -> __tcp_push_pending_frames() ->

tcp_write_xmit()

如果函数tcp_write_xmit()有发送数据成功,不论发送了多少个数据包,它都将返回0;但如果一个数据包也未发送,比如可能受当前拥塞窗口和发送窗口的限制,也可能是受选项TCP_CORK(函数tcp_write_xmit()内会调用tcp_nagle_test()函数做数据包发送判断)等的影响,导致数据包暂不能发送,此时就可能返回1:

由于TCP_CORK选项是Linux特有的,在其他比如BSD平台上,与此对应的是TCP_NOPUSH选项,所以在nginx内部通过函数ngx_tcp_nopush()/ngx_tcp_push()来分别对应启用/禁用TCP_CORK选项,达到各个平台的一致性封装。

第152行的if判断给出了需设置TCP_CORK选项的前提条件,变量c->tcp_nopush的值为NGX_TCP_NOPUSH_UNSET则表示TCP_CORK选项当前处于禁用状态,所以才需要进入到if块内去执行函数ngx_tcp_nopush()启用TCP_CORK选项;值得注意的是,禁用状态并不是表示nginx不使用TCP_CORK选项,如果设置为不使用该选项,那么对应该变量的值则为NGX_TCP_NOPUSH_DISABLED。第153-155的判断为真则表示响应头和响应体同时存在,并且响应体在文件内;为什么要把“响应体在文件内”作为一个是否启用TCP_CORK选项的条件,原因在后面《数据读/写传输方式》一节对系统函数writev()进行描述时有讲到,在这里简单的说一句就是:如果待发送数据全部都在内存缓冲区,那么使用系统函数writev()可达到更好的效果,从而无需使用TCP_CORK选项。另外,由于nginx对选项TCP_CORK和TCP_NODELAY是互斥使用,所以有底189行的if判断。开启TCP_CORK选项发送完响应数据后,在连接结束的其中一个处理函数,也就是ngx_http_set_keepalive()内又将禁用TCP_CORK选项,即拔掉塞子,让阻塞的数据可以发送出去,但是否立即发送出去还需由选项TCP_NODELAY以及Nagle算法决定。

对于选项TCP_CORK和TCP_NODELAY,除了前面提到的这些使用逻辑之外,在nginx的upstream模块也有对应的使用,不过都比较简单而不多累述,但要注意的就是,nginx始终是在互斥使用这两个选项,也正因为如此,为了避免错误的认为这两个选项必须互斥使用,下面就介绍一下这两个选项的混合使用情况。

对于一个套接口描述符,选项TCP_NODELAY和TCP_CORK可以同时存在,这是无容置疑的。看一下内核里设置两个选项时所对应的操作:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

2129: Filename :

\linux-3.4.4\net\ipv4\tcp.c

2130: static int do_tcp_setsockopt(struct

sock *sk, int level,

2131:

int optname, char __user *optval, unsigned int optlen)

2132: {

2133: …

2268:

case TCP_NODELAY:

2269:

if (val) {

2270: …

2278: tp->nonagle |= TCP_NAGLE_OFF|TCP_NAGLE_PUSH;

2279: tcp_push_pending_frames(sk);

2280: } else {

2281: tp->nonagle &= ~TCP_NAGLE_OFF;

2282: }

2283:

break;

2284: …

2299:

case TCP_CORK:

2300: …

2311:

if (val) {

2312: tp->nonagle |= TCP_NAGLE_CORK;

2313: } else {

2314: tp->nonagle &= ~TCP_NAGLE_CORK;

2315:

if (tp->nonagle&TCP_NAGLE_OFF)

2316: tp->nonagle |= TCP_NAGLE_PUSH;

2317: tcp_push_pending_frames(sk);

2318: }

2319:

break;

前面已经提到过,如果选项TCP_CORK存在,那么选项TCP_NODELAY的作用将被弱化,这在函数tcp_nagle_check()里能看到这一点,而对应的TCP_NAGLE_CORK旗标正好在第2312行里设置,也就是启用TCP_CORK选项时打上该标记;从第2315-2317代码可以看出,只有当选项TCP_CORK被清除后,选项TCP_NODELAY的作用才会体现出来,但是存在一个特别的时间点,也就是在开启选项TCP_NODELAY时,如第2278-2279行所示,此时会设置TCP_NAGLE_PUSH旗标,而后调用tcp_push_pending_frames()函数,把当前发送队列的数据包强制发送(即PUSH)出去,即便当前设置有选项TCP_CORK,在前面提到的函数tcp_nagle_test()里对TCP_NAGLE_PUSH旗标的特殊处理论证了这一点。当有新的数据包被加入到发送队列时,会调用函数skb_entail()清除TCP_NAGLE_PUSH标记,对于此时的这些数据包(新加进来的数据包以及在这个新数据包加进来之前还没发送完的旧数据包),选项TCP_CORK才又占主导地位:

1

2

3

4

5

6

7

535: Filename

: \linux-3.4.4\net\ipv4\tcp.c

536:

static inline void skb_entail(struct

sock *sk, struct sk_buff *skb)

537: {

538: …

549:

if (tp->nonagle & TCP_NAGLE_PUSH)

550: tp->nonagle &= ~TCP_NAGLE_PUSH;

551: }

linux tcp cork,Socket选项系列之TCP_CORK(转)相关推荐

  1. Linux网络编程 | socket选项设定 及 网络信息API

    文章目录 读取和设置 socket 选项 SO_REUSEADDR SO_RCVBUF 和 SO_SNDBUF SO_RCVLOWAT 和 SO_SNDLOWAT SO_LINGER 选项 网络信息A ...

  2. linux tcp cork,在此用例中,TCP_CORK和TCP_NODELAY是否有显着差异?

    在写完关于TCP_NODELAY和TCP_CORK的答案之后,我意识到我必须缺少对TCP_CORK的要点的了解,因为我尚不清楚100%为何Linux开发人员认为有必要引入一个新的TCP_CORK标志, ...

  3. 套接字socket选项TCP_NODELAY、TCP_CORK与TCP_QUICKACK

    一.简介: TCP_NODELAY关闭Nagle算法,控制的是数据的发送.Nagle 算法规定,如果包大于MSS(Max Segment Size)或含有FIN则立即发送,否则放入缓冲区,等已经发送的 ...

  4. linux tcp阻塞socket recv接收数据 未达到指定长度返回问题

    一直以为在阻塞的tcp socket上使用read/recv读取的数据长度一定和指定的读取长度一致,但是实际测试时发现往往返回的长度都比指定长度短,查找资料发现其实是一直误解了这个函数.    引用& ...

  5. Linux TCP/IP协议栈之Socket的实现分析

    数据包的接收 作者:kendo http://www.skynet.org.cn/viewthread.php?tid=14&extra=page%3D1 Kernel:2.6.12 一.从网 ...

  6. Linux Kernel TCP/IP Stack — Socket Layer — TCP/UDP Socket 网络编程

    目录 文章目录 目录 TCP/UDP Socket 逻辑架构 创建 Socket 绑定 Socket 请求建立 Socket 连接 监听 Socket 接受请求 关闭连接 数据的发送和接收 send ...

  7. Linux 高性能服务器编程——socket选项

    socket选项函数 功能:用来读取和设置socket文件描述符属性的方法 函数: #include <sys/scoket.h> int getsockopt ( int sockfd, ...

  8. linux 协议栈之socket,Linux TCP/IP 协议栈之 Socket 的实现分析(一)

    内核版本:2.6.37 参考[作者:kendo的文章(基于内涵版本2.6.12)] 第一部份 Socket套接字的创建 socket 并不是 TCP/IP协议的一部份. 从广义上来讲,socket 是 ...

  9. c语言linux TCP长连接 socket收发范例 断开自动重连

    原文链接:https://blog.csdn.net/chenhao0568/article/details/103420615 c语言linux TCP长连接 socket收发范例 断开自动重连 改 ...

最新文章

  1. 3个题目熟悉类和对象基础
  2. python各个解释器的用途-11 个优秀的 Python 编译器和解释器
  3. PBRT笔记(2)——BVH
  4. ubuntu16.04分区
  5. python numpy 中 np.mean(a) 跟 a.mean() 的区别
  6. Github 个人首页档案资料卡 README 自述文件
  7. linux signal 符号表6,gdb调试信息__000_linux-gnu_00000000_002_rw-p__169IT.COM
  8. Libvirt虚拟机的Qos与Cgroup
  9. 更新整理本人所有博文中提供的代码与工具(Java,2013.08)
  10. ionic 图片显示在屏幕中间_iPad屏幕坏点亮点怎么看 自查iPad屏幕坏点亮点方法【详解】...
  11. 树莓派 不稳定 ssh经常断 解决
  12. DM860步进电机接线及拨码
  13. html5 shiv
  14. SUI Mobile 手机移动端H5框架
  15. 二阶无源低通滤波器幅频特性曲线_一文看懂二阶lc低通滤波器的设计及原理
  16. 数据类型--Number类型
  17. 微信电脑版多用户登录
  18. 【面经】Linux零碎系列
  19. 脏读、幻读和不可重复读
  20. springboot多线程等待所有结果返回

热门文章

  1. Java实训项目13:GUI学生信息管理系统 - 实现步骤 - 创建应用程序类
  2. 【BZOJ2154】Crash的数字表格,数论练习之二维LCM(莫比乌斯反演)
  3. 【Tyvj1783】【codevs2418】【BZOJ1856】字符串,厉害的组合数与模型转换
  4. 提供做某事Do you want me to..._45
  5. 如何维持手机电池寿命_手机电池不耐用,都怪这些充电坏毛病
  6. css专业名词,CSS进阶系列一(flex布局基础知识——介绍、规范、主要思想、专业术语)...
  7. 只调用一次_邹军:数控宏程序编程入门之程序的调用,老师傅用了都说好
  8. easyui 添加下拉框数据_功能更新:熟用仪表盘这个功能,你可以少建90%的数据报表...
  9. 2017.3.7 搞笑世界杯 失败总结
  10. github issue 搜索_回顾 2020 年 GitHub 的大事件,你知道多少?