前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >TCP报文发送的那些事

TCP报文发送的那些事

作者头像
程序员历小冰
发布于 2019-04-25 07:18:22
发布于 2019-04-25 07:18:22
1.4K0
举报
文章被收录于专栏:程序员历小冰程序员历小冰

 今天我们来总结学习一下TCP发送报文的相关知识,主要包括发送报文的步骤,MSS,滑动窗口和Nagle算法。

发送报文

 该节主要根据陶辉大神的系列文章总结而来。如下图所示,我们一起来看一下TCP发送报文时操作系统内核都做了那些事情。其中有些概念在接下来的小节中会介绍。

 首先,用户程序在用户态调用send方法来发送一段较长的数据。然后send函数调用内核态的tcp_sendmsg方法进行处理。

 主要注意的是,send方法返回成功,内核也不一定真正将IP报文都发送到网络中,也就是说内核发送报文和send方法是不同步的。所以,内核需要将用户态内存中的发送数据,拷贝到内核态内存中,不依赖于用户态内存,使得进程可以快速释放发送数据占用的用户态内存。

 在拷贝过程中,内核将待发送的数据,按照MSS来划分成多个尽量接近MSS大小的分片,放到这个TCP连接对应的tcp_write_queue发送队列中。

 内核中为每个TCP连接分配的内核缓存,也就是tcp_write_queue队列的大小是有限的。当没有多余的空间来复制用户态的待发送数据时,就需要调用sk_stream_wait_memory方法来等待空间,等到滑动窗口移动,释放出一些缓存出来(收到发送报文相对应的ACK后,不需要再缓存该已发送出的报文,因为既然已经确认对方收到,就不需要重发,可以释放缓存)。

 当这个套接字是阻塞套接字时,等待的超时时间就是SO_SNDTIMEO选项指定的发送超时时间。如果这个套接字是非阻塞套接字,则超时时间就是0。也就是说,sk_stream_wait_memory对于非阻塞套接字会直接返回,并将 errno错误码置为EAGAIN。

 我们假定使用了阻塞套接字,且等待了足够久的时间,收到了对方的ACK,滑动窗口释放出了缓存。所以,可以将剩下的用户态数据都组成MSS报文拷贝到内核态的缓存队列中。

 最后,调用tcp_push等方法,它最终会调用IP层的方法来发送tcp_write_queue队列中的报文。注意的是,IP层方法返回时,也不意味着报文发送了出去。

 在发送函数处理过程中,Nagle算法、滑动窗口、拥塞窗口都会影响发送操作。

MTU和MSS

 我们都知道TCP/IP架构有五层协议,低层协议的规则会影响到上层协议,比如说数据链路层的最大传输单元MTU和传输层TCP协议的最大报文段长度MSS。

 数据链路层协议会对网络分组的长度进行限制,也就是不能超过其规定的MTU,例如以太网限制为1500字节,802.3限制为1492字节。但是,需要注意的时,现在有些网卡具备自动分包功能,所以也可以传输远大于MTU的帧

 网络层的IP协议试图发送报文时,若报文的长度大于MTU限制,就会被分成若干个小于MTU的报文,每个报文都会有独立的IP头部。IP协议能自动获取所在局域网的MTU值,然后按照这个MTU来分片。IP协议的分片机制对于传输层是透明的,接收方的IP协议会根据收到的多个IP包头部,将发送方IP层分片出的IP包重组为一个消息。

 这种IP层的分片效率是很差的,因为首先做了额外的分片操作,然后所有分片都到达后,接收方才能重组成一个包,其中任何一个分片丢失了,都必须重发所有分片。

 所以,TCP层为了避免IP层执行数据报分片定义了最大报文段长度MSS。在TCP建立连接时会通知各自期望接收到的MSS的大小。

 需要注意的是MSS的值是预估值。两台主机只是根据其所在局域网的计算MSS,但是TCP连接上可能会穿过许多中间网络,这些网络分别具有不同的数据链路层,导致问题。比如说,若中间途径的MTU小于两台主机所在的网络MTU时,选定的MSS仍然太大了,会导致中间路由器出现IP层的分片或者直接返回错误(设置IP头部的DF标志位)。

 比如阿里中间件的这篇文章[1](链接不见的话,请看文末)所说,当上述情况发生时,可能会导致卡死状态,比如scp的时候进度卡着不懂,或者其他更复杂操作的进度卡死。

滑动窗口

 IP层协议属于不可靠的协议,IP层并不关心数据是否发送到了接收方,TCP通过确认机制来保证数据传输的可靠性。

 除了保证数据必定发送到对端,TCP还要解决包乱序(reordering)和流控的问题。包乱序和流控会涉及滑动窗口和接收报文的out_of_order队列,另外拥塞控制算法也会处理流控,详情请看TCP拥塞控制算法简介

 TCP头里有一个字段叫Window,又叫Advertised-Window,这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,否则会导致接收端处理不过来。

 我们可以将发送的数据分为以下四类,将它们放在时间轴上统一观察。

  • Sent and Acknowledged: 表示已经发送成功并已经被确认的数据,比如图中的前31个字节的数据
  • Send But Not Yet Acknowledged:表示发送但没有被确认的数据,数据被发送出去,没有收到接收端的ACK,认为并没有完成发送,这个属于窗口内的数据。
  • Not Sent,Recipient Ready to Receive:表示需要尽快发送的数据,这部分数据已经被加载到缓存等待发送,也就是发送窗口中。接收方ACK表示有足够空间来接受这些包,所以发送方需要尽快发送这些包。
  • Not Sent,Recipient Not Ready to Receive:表示属于未发送,同时接收端也不允许发送的,因为这些数据已经超出了发送端所接收的范围

 除了四种不同范畴的数据外,我们可以看到上边的示意图中还有三种窗口。

•Window Already Sent:已经发送了,但是没有收到ACK,和Send But Not Yet Acknowledged部分重合。•Usable Window : 可用窗口,和Not Sent,Recipient Ready to Receive部分重合•Send Window: 真正的窗口大小。建立连接时接收方会告知发送方自己能够处理的发送窗口大小,同时在接收过程中也不断的通告能处理窗口的大小,来实时调节。

 下面,我们来看一下滑动窗口的滑动。下图是滑动窗口滑动的示意图。

 当发送方收到发送数据的确认消息时,会移动发送窗口。比如上图中,接收到36字节的确认,将其之前的5个字节都移除发送窗口,然后46-51的字节发出,最后将52到56的字节加入到可用窗口。

 下面我们来看一下整体的示意图。

 图片来源为tcpipguide.

 client端窗口中不同颜色的矩形块代表的含义和上边滑动窗口示意图中相同。我们只简单看一下第二三四步。接收端发送的TCP报文window为260,表示发送窗口减少100,可以发现黑色矩形缩短了,也就是发送窗口减少了100。并且ack为141,所以发送端将140个字节的数据从发送窗口中移除,这些数据从Send But Not Yet Acknowledged变为Sent and Acknowledged,也就是从蓝色变成紫色。然后发送端发送180字节的数据,就有180字节的数据从Not Sent,Recipient Ready to Receive变为Send But Not Yet Acknowledged,也就是从绿色变为蓝色。

Nagle算法

 上述滑动窗口会出现一种Silly Window Syndrome的问题,当接收端来不及取走Receive Windows里的数据,会导致发送端的发送窗口越来越小。到最后,如果接收端腾出几个字节并告诉发送端现在有几个字节的window,而我们的发送端会义无反顾地发送这几个字节。

 只为了发送几个字节,要加上TCP和IP头的40多个字节。这样,效率太低,就像你搬运物品,明明一次可以全部搬完,但是却偏偏一次只搬一个物品,来回搬多次。

 为此,TCP引入了Nagle算法。应用进程调用发送方法时,可能每次只发送小块数据,造成这台机器发送了许多小的TCP报文。对于整个网络的执行效率来说,小的TCP报文会增加网络拥塞的可能。因此,如果有可能,应该将相临的TCP报文合并成一个较大的TCP报文(当然还是小于MSS的)发送。

 Nagle算法的规则如下所示(可参考tcp_output.c文件里tcp_nagle_check函数注释):

•如果包长度达到MSS,则允许发送;•如果该包含有FIN,则允许发送;•设置了TCP_NODELAY选项,则允许发送;•未设置TCP_CORK选项时,若所有发出去的小数据包(包长度小于MSS)均被确认,则允许发送;•上述条件都未满足,但发生了超时(一般为200ms),则立即发送。

当对请求的时延非常在意且网络环境非常好的时候(例如同一个机房内),Nagle算法可以关闭。使用TCP_NODELAY套接字选项就可以关闭Nagle算法

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-04-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员历小冰 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
高性能网络编程2—-TCP消息的发送
在上一篇中,我们已经建立好的TCP连接,对应着操作系统分配的1个套接字。操作TCP协议发送数据时,面对的是数据流。通常调用诸如send或者write方法来发送数据到另一台主机,那么,调用这样的方法时,在操作系统内核中发生了什么事情呢?我们带着以下3个问题来细细分析:发送方法成功返回时,能保证TCP另一端的主机接收到吗?能保证数据已经发送到网络上了吗?套接字为阻塞或者非阻塞时,发送方法做的事情有何不同?
陶辉
2019/06/21
8720
高性能网络编程2—-TCP消息的发送
高性能网络编程2----TCP消息的发送
http://blog.csdn.net/russell_tao/article/details/9370109
bear_fish
2018/09/20
8760
高性能网络编程2----TCP消息的发送
Java程序员必须掌握的网站知识 —— TCP
本文主要通过整理网络上的资料,整理出的关于TCP方面的简单理论知识。作为Java程序员虽然更多的时候我们都是直接调用现成的API,但是对网络知识有个宏观的概念能方便我们更好的编写代码。当然,文中涉及的
tomas家的小拨浪鼓
2018/06/27
1.1K0
八股文!!
在发送数据包时,首先确认IP包中的目的IP地址,再从路由控制表中找到与该地址具有相同网络地址的记录,将包转发给该记录对应的路由器。如果路由控制表中有多条相同网络地址的记录,利用贪心法选择最优匹配项,如果没有匹配项,转发到默认路由后再进行选路。例如:目标地址172.20.100.52
千羽
2021/12/29
1.1K0
八股文!!
TCP粘包、拆包与通信协议详解
在TCP编程中,我们使用协议(protocol)来解决粘包和拆包问题。本文将详解TCP粘包和半包产生的原因,以及如何通过协议来解决粘包、拆包问题。让你知其然,知其所以然。
田守枝
2019/05/21
11.5K0
TCP粘包、拆包与通信协议详解
TCP协议和UDP协议
1.1.2每一条TCP连接只能有两个端点,每一条TCP链接只能是点对点的(一对一)
全栈程序员站长
2022/06/26
1.3K0
TCP协议和UDP协议
TCP三次握手和四次挥手?TCP如何保证可靠性?什么是TCP滑动窗口?
应用数据被分割成TCP认为最适合发送的数据块。这和UDP完全不同,应用程序产生的数据报长度将保持不变。
一个会写诗的程序员
2020/04/24
7880
TCP三次握手和四次挥手?TCP如何保证可靠性?什么是TCP滑动窗口?
网络知识扫盲:扒开 TCP 的外衣,我看清了 TCP 的本质
从阅读和在看数来看,大家对这个系列还是比较期待的,所以这周我全身心地投入本篇文章的编写,用了整整 4个晚上的时间梳理了这篇关于 TCP 的重点知识,另外还参考 小林 coding 的文章配图,用了一天的时间自己制作了 TCP 三次握手和四次挥手的图解,对你理解 TCP 连接一定会有帮助。
Python进阶者
2021/01/25
7440
网络知识扫盲:扒开 TCP 的外衣,我看清了 TCP 的本质
1万字30张图说清TCP协议
TCP(Transmission Control Protocol 传输控制协议)是一种基于IP的传输层协议,TCP协议面向连接、正面确认与重传、缓冲机制、流量控制、差错控制、拥塞控制,可保证高可靠性(数据无丢失、数据无失序、数据无错误、数据无重复到达)传输层协议。
网络工程师笔记
2021/05/17
1.4K0
1万字30张图说清TCP协议
TCP协议要点和难点全解
TCP协议要点和难点全解 说明: 1).本文以TCP的发展历程解析容易引起混淆,误会的方方面面 2).本文不会贴大量的源码,大多数是以文字形式描述,我相信文字看起来是要比代码更轻松的 3).针对对象:对TCP已经有了全面了解的人。因为本文不会解析TCP头里面的每一个字段或者3次握手的细节,也不会解释慢启动和快速重传的定义 4).除了《TCP/IP详解》(卷一,卷二)以及《Unix网络编程》以及Linux源代码之外,学习网络更好的资源是RFC 5).本文给出一个提纲,如果想了解细节,请直接查阅RFC 6).
用户1289394
2018/02/27
1.4K0
TCP/IP具体解释–TCP/UDP优化设置总结& MTU的相关介绍「建议收藏」
当中以太网(Ethernet)的数据帧在链路层    IP包在网络层    TCP或UDP包在传输层    TCP或UDP中的数据(Data)在应用层    它们的关系是 数据帧{IP包{TCP或UDP包{Data}}}    ——————————————————————————— 在应用程序中我们用到的Data的长度最大是多少,直接取决于底层的限制。    我们从下到上分析一下:    1.在链路层,由以太网的物理特性决定了数据帧的长度为(46+18)-(1500+18),当中的18是数据帧的头和尾,也就是说数据帧的内容最大为1500(不包含帧头和帧尾)。即MTU(Maximum Transmission Unit)为1500;   2.在网络层。由于IP包的首部要占用20字节,所以这的MTU为1500-20=1480;  3.在传输层,对于UDP包的首部要占用8字节。所以这的MTU为1480-8=1472。    所以,在应用层,你的Data最大长度为1472。
全栈程序员站长
2022/07/10
1.9K0
TCP报文头部(sip协议端口号是tcp还是udp)
大家好,我是架构君,一个会写代码吟诗的架构师。今天说一说TCP报文头部(sip协议端口号是tcp还是udp),希望能够帮助大家进步!!!
Java架构师必看
2022/04/11
2.3K0
TCP报文头部(sip协议端口号是tcp还是udp)
计算机网络之运输层1 功能2 UDP与TCP异同可靠传输的工作原理可靠传输的实现TCP 报文段的首部格式TCP 的流量控制TCP的拥塞控制
1 功能 1.1 进程间通信 从通信和信息处理的角度看,运输层向应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最底层 当网络的边缘部分中的两个主机使用网络的核心部分的功能进行端
JavaEdge
2018/05/16
1.3K0
传输层协议TCP与UDP
主机是用IP地址来标识的,而要标识主机中的进程,就需要使用端口号。TCP/IP协议族中,端口号占16 bit,用0~65535之间的整数标识。TCP和UDP是两个独立的软件模块,因此各自的端口号也相互独立。·端口号只具有本地意义,不同计算机的相同端口号是没有联系的。
十二惊惶
2024/02/28
6520
传输层协议TCP与UDP
3-传输层
传输层是整个TCP/IP协议栈核心之一,位于网络层之上,应用层之下。利用网络层的服务,为上层应用层提供服务。与网络层类似,传输层也拥有面向连接的服务与无连接的服务两种,用途在于提供高效的可靠的,性价比高的数据传输
Ywrby
2022/10/27
1.3K0
3-传输层
TCP协议
•使用TCP进行通信,在传输数据前需要建立连接,连接建立成功之后才能输出数据。建立连接的两端分配内核资源,像端口号,socket描述符。建立连接的过程需要3步,称这个过程为3次握手。
数据小冰
2022/08/15
1.1K0
TCP协议
在深谈TCP/IP三步握手&四步挥手原理及衍生问题—长文解剖IP
如果对网络工程基础不牢,建议通读《细说OSI七层协议模型及OSI参考模型中的数据封装过程?》
周陆军
2018/11/14
1.6K0
高性能网络编程7--tcp连接的内存使用
当服务器的并发TCP连接数以十万计时,我们就会对一个TCP连接在操作系统内核上消耗的内存多少感兴趣。socket编程方法提供了SO_SNDBUF、SO_RCVBUF这样的接口来设置连接的读写缓存,linux上还提供了以下系统级的配置来整体设置服务器上的TCP内存使用,但这些配置看名字却有些互相冲突、概念模糊的感觉,如下(sysctl -a命令可以查看这些配置): net.ipv4.tcp_rmem = 8192 87380 16777216 net.ipv4.tcp_wmem = 8192 65536
李海彬
2018/03/23
2K0
高性能网络编程7--tcp连接的内存使用
【Linux】传输层协议:UDP和TCP
1. 在网络通信中,通信的本质实际就是两台主机上的进程在网络环境中进行通信,也就是数据的传输,而我们总说TCP/IP协议栈,这两个协议分别解决了两个重要的问题,即一台主机如何在网络环境中标定自己的唯一性,一台主机中的某个进程如何在主机内部标定自己的唯一性,实际就是通过网络层协议IP地址和传输层协议端口号port来解决这两个问题的。
举杯邀明月
2023/10/17
1.3K0
【Linux】传输层协议:UDP和TCP
这次,终于学会了 TCP
这是一篇详细介绍 TCP 各种特点的文章,内容主要包括 TCP 三次握手和四次挥手细节问题、TCP 状态之间的转换、TCP 超时和重传、关于 TCP 包失序和重复问题、TCP 的数据流与窗口管理、TCP 的拥塞控制,思维导图如下。
cxuan
2021/07/12
8330
这次,终于学会了 TCP
推荐阅读
相关推荐
高性能网络编程2—-TCP消息的发送
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档