整理自 CSDN 公众号
1 客户端
TCP 三次握手的开始是客户端发起 SYN,如果服务端没有及时回复,那么会重传,重传的间隔和次数是可控的,默认是五次,第一次间隔 1 秒,第二次 2 秒,第三次 4 秒,第四次 8 秒,第五次16 秒,最终超时时间是 63 秒,因此在优化时可以修改重传次数和间隔,以尽快把错误暴露给应用程序。
2 服务端的半连接队列优化
服务端在第一次返回 SYN + ACK 时,就会把这次请求维护进一个半连接队列,这个队列用来维护尚未完成的握手信息(相对于全连接),如果这个队列溢出了,服务端就无法继续接受新的请求了,这也是 SYN Flood 攻击的点。
通过一个命令 netstat -s 可以得到累计的、由于半连接队列已满引发的失败次数,隔几秒执行一次就可以知道这个次数是否有上升的趋势以及分析是否正常。
这种 SYN Flood 攻击之所以成立,是因为维护这个半连接队列一定要分配一定的内存资源,那么应对的方式之一 syncookies 就是如何不分配资源的前提下,可以确认是一次有效的连接并 establish。
syncookies 的工作原理是,服务器使用一种算法,计算出一个哈希值,它包含了客户端发来请求的部分信息,再将这个哈希值和 SYN+ACK 一起返回给客户端,客户端也经过一些运算,再返回给服务端,那么服务端根据这个返回值和之前的计算值比较,如果合法,就可以建立有效连接,从而不会占据半连接队列的内存。应对 SYN 攻击时,只需将 syncookies 的参数值调为 1(半连接队列溢出时启用),即可。
相当的,可以增大半连接队列,但是要和 accept 的队列同时增大才有效,(否则会导致 accept 队列溢出同样丢失 TCP 连接)
此时,对于客户端来说已经是 established 状态,但是还要再返回给服务端一个 ACK,服务端收到后,服务端才是 established 状态并开始传数据,如果网络不稳定,同样的,服务端会重发 SYN+ACK,当网络不稳定时,应该增加服务端重发 SYN+ACK 的次数。
3 服务端的 accept 队列优化
当连接已经建立、应用程序尚未调用时,TCP 连接会被保存在一个 accept 队列中,如果进程未能及时调用,就会导致 accept 队列溢出,溢出部分连接将被默认丢弃。对此可以做的是,选择向客户端发送 RST 报文,告知关闭这个连接,丢弃握手过程。打开这一功能需要将 tcp_abort_on_overflow 参数设置为 1。如果想让客户端了解是由于 accept 队列溢出造成连接失败可以这样做。当 tcp_abort_on_overflow 参数设置为 0 时,则如果 accept 队列溢出,就会丢弃客户端传来的 ACK(用于最后一次握手)。
应对高并发流量时,更好的选择是 tcp_abort_on_overflow 参数设置为 0,这样对于客户端它的状态仍然是 established,客户端会定时发送带有 ack 报文的发送数据请求,一旦服务端的 accept 队列有空位,那么连接仍有可能建立成功。所以只有很确定在一段时间内 accept 都是将溢出的状态,才推荐 tcp_abort_on_overflow 参数设置为 1。
同样的,可以调整 accept 队列长度,也可以查看累计的由于溢出导致丢失的连接总数,来判断趋势。
在 Linux 37 内核版本之后,提供了 TCP Fast Open 功能,这个功能如此生效:
初次建立 TCP 连接时,客户端在第一个 SYN 包中传入一个请求 cookie,表明打开 fast open 功能,服务端对应生成一个 cookie 给客户端,除此之外,三次握手没有不同,但是,在 cookie 没有过期之前,下一次再连接的时候,客户端发送带有 cookie 的 SYN 包,服务端校验了 cookie 有效以后,就可以开始传输数据了,从而节约了一个往返的时间消耗。
TCP Fast Open 功能需要服务端和客户端同时打开才能生效。
(备注一个之前看到差点忘了的知识点。
当主动方收到被动方的 FIN 报文后,内核会回复 ACK 报文给被动方,同时主动方的连接状态由 FIN_WAIT2 变为 TIME_WAIT,在 Linux 系统下大约等待 1 分钟后,TIME_WAIT 状态的连接才会彻底关闭。
1 主动方的优化
关闭的方式有两种 RST 和 FIN,RST 是暴力关闭连接的方式,安全关闭连接则必须四次挥手。
FIN 报文关闭则可以使用 close 和 shutdown 两种函数来实现。close 相对来说是“不优雅”的,调用 close 的一方的连接叫做「孤儿连接」,会同时关闭读和写,而 shutdown 可以控制是读还是写。
关闭读的时候,会丢弃接收缓冲区里的所有数据,如果后续再接受到数据,也会悄悄丢弃,并发送 ACK,对方不会知道被丢弃了。
关闭写的时候,会把发送缓冲区的数据全部发送并发送 FIN。
(1)FIN_WAIT1 的优化
主动方发送 FIN 以后,进入 FIN_WAIT1 状态,如果迟迟没收到 ACK,会定时重发 FIN,重发次数由 tcp_orphan_retries 参数控制,默认为 8 次,如果处于 FIN_WAIT1 状态的连接过多,应该考虑降低次数,重发次数超过参数时,连接会被直接关闭。
如果遇到恶意攻击,可能无法发送出 FIN,因为 TCP 按顺序发送所有包, FIN 也不能绕过,另外如果对方的接收窗口已经满了,发送方也无法再发送数据。
此时应该做的是调整 tcp_max_orphans 参数,它定义了「孤儿连接」的最大数量,当系统中的孤儿连接超过参数值,新增的孤儿连接不会再处于 FIN_WAIT1 状态,而是会被 RST 报文直接关闭。(只会影响 CLOSE 函数关闭的连接,不会影响 shutdown 关闭的,不会影响还有读或写的可能)
(2)FIN_WAIT2 的优化
主动方收到 ACK 后,会处于 FIN_WAIT2,因为被动方还可能有数据发送,如果是 shutdown 关闭,那它也可能还会发送数据,但是对于 close 关闭的连接,无法再发送和接收数据,保持在 FIN_WAIT2 的状态已经没有太大意义,tcp_fin_timeout 控制了这个状态下连接的持续时长,默认值是 60 秒。这个时间和 TIME_WAIT 状态时长是一致的。
(3)TIME_WAIT 的优化
TIME_WAIT 和 FIN_WAIT2 的时间是一致的,都是 2MSL,1MSL 表示一个报文在网络中存活的最长时间(报文每经过一次路由器的转发,IP 头部的 TTL 字段就会减 1,减到 0 时报文就被丢弃,这就限制了报文的最长存活时间),那么为什么是等待 2MSL 呢,其实就是允许报文至少丢失一次、再发送一次,这样第一个丢失了,等待的时间里第二个 ACK 还会到达,为什么不是 4MSL 以上呢,这是一个概率的问题,如果一个网络丢包率达到 1%,那么连续两次丢包的概率是万分之一,不必为了这种概率增加等待的时长。
TIME_WAIT 有存在的意义,但是太多保持在这种状态的连接会占用双方资源,占据客户端的端口资源和服务端的系统资源。
Linux 提供了 tcp_max_tw_buckets 参数,当 TIME_WAIT 的连接数量超过该参数时,新关闭的连接就不再经历 TIME_WAIT 而直接关闭。这个参数的设定应该取一个平衡点,即既不会太少导致高并发时产生连接间数据错乱的问题,也不会太多而导致耗尽端口和线程资源。
对于用户端来讲,还可以启用 tcp_tw_reuse 参数来复用处于 TIME_WAIT 状态的连接(来节约接口资源。)这个参数有几个前提,一个是只有客户端可以打开,一个是 TIME_WAIT 状态也要保持 1 秒,另一个是要同步打开时间戳功能,报文带上时间戳就可以避免没有了 2MSL 时长以后的混乱情况,时间戳过期的报文就会被丢掉。
另外对于 TIME_WAIT,还可以调整 socket 选项,来达到调用 close 关闭连接时跳过四次挥手直接关闭的效果,但不推荐。
2 被动方的优化
首先,被动方收到 FIN 时,会自动回复 ACK,接着等待应用程序调用 close/shutdown 来结束连接,再发送 FIN。如果系统中同时查看到多个连接处于 CLOSE_WAIT 状态,则需要排查是否是应用程序出了故障。
然后,当被动方也发送了 FIN 以后,还需要等待主动方回复一个 ACK,如果迟迟没收到,也会重发 FIN,重发次数也是 tcp_orphan_retries 参数控制,这点和主动方的优化一致,可以调整次数。(需确认被动方是否有 tcp_max_orphans 参数)
3 如果双方同时关闭?
1 ACK 延迟
目前在 TCP 中每传输一个报文都要求接收方进行确认,大量短而频繁的确认报文给网络带来了很多开销。因此采取了延迟 ACK 策略来减少 ACK 的数量,就是接收方收到一个报文以后,不会立即发送 ACK,而是等待 1~200ms,这期间若有回送数据报文就捎带确认,但收到两个连续数据报文或者等待超时则发送一个独立确认。有效减少了 ACK 的数量,改善了 TCP 的整体性能。
2 滑动窗口
接收方的接收缓冲区不是不变的,接收到新的会变小,应用程序取出后又会变大,因此接收方会把自己当前的接收窗口大小放在 TCP 头告知发送方,如果不考虑拥塞控制,发送方的窗口大小「约等于」接收方的窗口大小。
对于这一点,可以把 tcp_window_scaling 配置设为 1(默认打开)来扩大 TCP 通告窗口至 1G 大小。要使用这一选项,需要主动方在 SYN 中先告知,被动方在 SYN 中再反馈。
但是缓冲区并非越大越好,还要考虑网络吞吐的能力。如果缓冲区与网络传输能力匹配,那么缓冲区的利用率就达到了最大化。
3 调整缓冲区大小
这里需要说一个概念,就是带宽时延积,它决定网络中飞行报文的大小,它的计算方式:
(1)发送缓冲区的调整
发送缓冲区是自行调节的,当发送方发送的数据被确认后,并且没有新的数据要发送,就会把发送缓冲区的内存释放掉。
接收缓冲区要复杂一些:
上面三个数字单位都是字节,它们分别表示:
(2)接收缓冲区的调整
接收缓冲区可以根据系统空闲内存的大小来调节接收窗口:
(3)内存的判断
那么如何判断内存紧张或充分呢?
上面三个数字单位不是字节,而是「页面大小」,1 页表示 4KB,它们分别表示:
在实际的场景中,TCP 缓冲区最小值保持默认 4K 即可,来提高并发处理能力;最大值则尽可能靠近带宽时延积,来最大化网络效率。
总结以上:为了提高并发能力、提高网络效率,我们要充分利用网络能力和自己的内存。网络这方面就是将缓冲区大小的极值尽可能靠近带宽时延积,而同时对缓冲区的自动调节需要结合内存来判断,这个 TCP 内存的判断是通过系统内存计算出来的几个值来划分的,在不同区间会对分配给缓冲区的内存大小进行调整。
以上就是 TCP 在不同阶段的优化策略和思路,有关拥塞控制和流量控制之后再补一篇笔记。
流量控制针对的是发送方和接收方速度不匹配的问题(比如经典的fast sender and slow receiver问题,接收方缓存大小与发送速率不匹配),所提供一种速度匹配服务,遏制发送速率使接收方应用程序的读取速率与之相适应。
主要的方法有:
滑动窗口协议是传输层进行流控的一种措施,接收方通过通告发送方自己的窗口大小,从而控制发送方的发送速度。
在TCP发送缓存内的数据都可以分为4类:
已经发送但还未收到对端ACK和未发送但对端允许发送这2部分数据称之为发送窗口。
ACK报文包含2个重要信息:
如此发送方在接收到的ACK包含的这2个数据后就可以计算出还可以发送多少字节的数据给对方,假定当前发送方已发送到第x个字节,则可以发送的字节数就是y=m-(x-n)。
从这个例子里我们可以总结一下几点:
由接收方提供的窗口大小通常可以由接收进程控制,Socket API允许进程设置发送和接收缓存大大小。 接收缓存的大小是该连接上所能够通告的最大窗口大下 。
在CentOS中,可以通过配置内核参数来调整网速。以下是一些常用的内核参数:
1 netcoresomaxconn:此参数指定了待处理请求的最大数目。如果您正在处理大量网络请求,可以适当增加该参数以提高性能。
2 netcorenetdev_max_backlog:此参数指定了网络设备队列的最大长度。如果队列长度太短,则可能出现数据包丢失的情况。可以适当增加该参数以提高网络吞吐量。
3 netipv4tcp_max_syn_backlog:此参数指了SYN队列的最大长度。如果队列长度太短,则可能无法处理所有的TCP连接请求。可以适当增加该参数以应对高负载情况。
4 netipv4tcp_fin_timeout:此参数指定了TCP连接终止时等待FIN确认的超时时间。如果该值设置太小,则可能导致服务中断;如果设置得太大,则可能导致资源浪费。可以根据实际情况适当调整该参数。
5 netipv4tcp_keepalive_time:此参数指定了TCP keepalive机制的启动时间。通过启用keepalive机制,可以在长时间空时检测到连接状态,并且避免连接空闲过久而被关闭。可以根据业务需要适当调整该参数。
6 netipv4tcp_tw_reuse:此参数指定是否开启TCP连接重用。启用该选项可以将处于TIME_WAIT状态的套接字重新分配给新连接,从而节省网络资源。但同时也可能导致一些安全问题。建议在生产环境下谨慎使用。
7 netipv4tcp_window_scaling:此参数指定了是否启用TCP窗口缩放。启用该选项可以在延迟的网络中提高吞吐量。议在高延迟的情况下启用该选项。
以上是一些常用的CentOS内核参数,可以通过修改/sys/文件系统中的相应文件来修改这些参数。为避免对系统造成不可逆的损害,请务必备份原有配置并在修改前详细了解参数的含义。
TCP:传输、 控制 、协议。
TCP与UDP最大却别就在那个 C 上面,它充分实现了数据传输时各种控制功能。可以进行丢包 重发控制 ,还可以对次序乱掉的数据包进行 顺序控制 ,还能 控制传输流量 ,这些是UDP中没有的。即T C P 提供一种面向连接的、可靠的字节流服务。
TCP是一中面向有链接的协议,只有在确认对端存在的时候,才会发送分数据,从而也可以控制通信流量的浪费。
什么是可靠的传输: 不丢包、不损坏、不乱序、不重复。
TCP通过 校验和 、 序列号 、 确认应答 、 重发控制 、 连接管理 以及 窗口控制 等机制来实现可靠传输。
接收端查询就收数据TCP首部中的序号和数据长度。将自己下一步应该接受的序列号作为确认应答返送回去。就这样,通过序列号和确认应答,TCP实现可靠传输。
一般使用TCP首部用于控制的字段来管理连接。一个连接的建立和断开,正常过程中,至少需要来回共7个包才能完成。
TCP首部的数据结构如图所示:
TCP包首部
为了便于理解,忽略选项部分,固定首部通常为20个字节,将按作用分类分析。
前4个字节 来标识了发送方的端口号和接收方的端口号,即该数据包由谁发送,由谁接收。前2个字节标识源端口号,紧接着2个字节标识目的端口号。
即发送方:(11111111,1111111) 2 = (65535) 10 ,除去0~1023
即接收方:(11111111,1111111) 2 = (65535) 10 ,除去0~1023
TCP是面向字节流的。 在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。首部中的序号字段值则是指的是本报文段所发送的数据的第一个字节的序号。长度为4字节,序号是32bit的无符号数,序号到达2 32 - 1后又从0开始。
ack :确认序号, <u style="box-sizing: border-box;">即确认字节的序号</u> ,更确切地说,是 发送确认的一端 所期望收到的下一个序号。
所谓的 发送确认的一端 就是将确认信息发出的一端。比如第二次握手的 S 端就是 发送确认的一端 。
确认序号为上次接收的最后一个字节序号加1只有确认标志位( ACK )为1的时候,确认序号才有效。
也叫首部长度,占4个bit,它指出TCP报文段的 数据 起始处距离TCP报文段的起始处有多远。
TCP报文结构
由于首部中还有长度不确定的选项字段,因此数据偏移字段是必要的。
“首部长度”是4位二进制数,单位是 32位字 ,能表示的最大十进制数字是15。
(1111) 2 =(15) 10 ,即是15个32位,一个32位是4个字节,因此数据偏移的最大值是15 4=60个字节,这也是TCP首部的最大字节。因为固定首部的存在,数据偏移的值最小为 20个字节 ,因此选项长度不能超过 40字节 (减去20个字节的固定首部)。
占6位,保留为今后使用,但目前应置为0。
当URG=1时,表明紧急指针字段有效。
它告诉系统此报文段中有紧急数据,应尽快发送(相当于高优先级的数据),而不要按原来的排队顺序来传送。
例如,已经发送了很长的一个程序要在远地的主机上运行。但后来发现了一些问题,需要取消该程序的运行,因此用户从键盘发出中断命令。如果不使用紧急数据,那么这两个字符将存储在接收TCP的缓存末尾。只有在所有的数据被处理完毕后这两个字符才被交付接收方的应用进程。这样做就浪费了很多时间。
当URG置为1时,应用进程就告诉TCP有紧急数据要传送。于是TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍然是普通数据。这时要与首部中 紧急指针 (Urgent Pointer)字段配合使用。
仅当ACK = 1时确认号字段才有效,当ACK = 0时确认号无效。TCP规定,在连接建立后所有的传送的报文段都必须把ACK置为1。
当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应。在这种情况下,TCP就可以使用推送(push) *** 作。发送方TCP把PSH置为1,并立即创建一个报文段发送出去。接收方TCP收到PSH=1的报文段,就尽快地(即“推送”向前)交付接收应用进程。而不用再等到整个缓存都填满了后再向上交付。
当RST=1时,表明TCP连接中出现了严重错误(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立传输连接。RST置为1还用来拒绝一个非法的报文段或拒绝打开一个连接。
在连接建立时用来同步序号。当 SYN=1 而 ACK=0 时,表明这是一个 连接请求报文段 。对方若同意建立连接,则应在响应的报文段中使SYN=1和ACK=1。
因此 SYN=1 就表示这是一个连接请求或连接接受报文。
用来释放一个连接。当FIN=1时,表明此报文段的发送发的数据已发送完毕,并要求释放运输连接。
占2字节。窗口值是(0,2 16 -1)之间的整数。
窗口指的是发送本报文段的一方的接受窗口(而不是自己的发送窗口),窗口大小是给对方用的。
窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方一次发送的数据量(以字节为单位)。
之所以要有这个限制,是因为接收方的数据缓存空间是有限的。
总之,窗口值作为接收方让发送方设置其发送窗口的依据。
例如,A发送了一个报文段,其确认号是3000,窗口字段是1000这就是告诉对方B:“从3000算起,A接收缓存空间还可接受1000个字节数据,字节序号是3000-3999”,可以想象到河道的阀门。
总之:窗口字段明确指出了现在允许对方发送的数据量。窗口值经常在动态变化。
占2字节。检验和字段检验的范围包括首部和数据这两部分。和UDP用户数据报一样,在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。伪首部的格式和UDP用户数据报的伪首部一样。但应把伪首部第4个字段中的17改为6(TCP的协议号是6);把第5字段中的UDP中的长度改为TCP长度。接收方收到此报文段后,仍要加上这个伪首部来计算检验和。若使用TPv6,则相应的伪首部也要改变。
占2字节。紧急指针仅在URG=1时才有意义,它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据) 。因此,在紧急指针指出了紧急数据的末尾在报文段中的位置。当所有紧急数据都处理完时,TCP就告诉应用程序恢复到正常 *** 作。值得注意的是,即使窗口为0时也可以发送紧急数据。
长度可变,最长可达40个字节。当没有使用“选项”时,TCP的首部长度是20字节。
最大报文段长度(MSS:Maximum Segment Size)表示TCP传往另一端的最大块数据的长度。当一个连接建立时,连接的双方都要通告各自的MSS。
当建立一个连接时,每一方都有用于通告它期望接收的MSS选项(MSS选项只能出现在SYN报文段中),如果一方不接收来自另一方的MSS值,则MSS就定为默认值536字节(这个默认值允许20字节的IP首部和20字节的TCP首部以适合576字节IP数据报) 。
为什么要规定一个最大报文长度MSS呢?
这并不是考虑接受方的接收缓存可能存放不下TCP报文段中的数据。实际上,MSS与接收窗口值没有关系。
我们知道,TCP报文段的数据部分,至少要加上40字节的首部( TCP首部20字节 和 IP首部20字节 ,这里还没有考虑首部中的可选部分)才能组装成一个 IP数据报 。
若选择较小的MSS长度,网络的利用率就降低。设想在极端情况下,当TCP报文段只含有1字节的数据时,在IP层传输的数据报的开销至少有40字节(包括TCP报文段的首部和IP数据报的首部)。这样,对网络的利用率就不会超过1/41。到了数据链路层还要加上一些开销。但反过来,若TCP报文段非常长,那么在IP层传输时就有可能要分解成多个短数据报片。在终点要把收到的各个短数据报片组成成原来的TCP报文段,当传输出错时还要进行重传,这些也都会使开销增大。
因此,MSS应尽可能大些,只要在IP层传输时不需要分片就行。
由于IP数据报所经历的路径是动态变化的,因此在这条路径上确定的不需要的分片的MSS,如果改走另一条路径就可能需要进行分片。因此最佳的MSS是很难确定的。在连接过程中,双方都把自己能够支持的MSS写入这一字段,以后就按照这个数值传输数据,两个传送方向可以有不同的MSS值。若主机未填写这一项,则MSS的默认值是536字节长。因此,所有在互联网上的主机都应该接受的报文段长度是536+20(固定首部长度)=556字节 。
后来又增加了几个选项如窗口扩大选项、时间戳选项等。
窗口扩大选项是为了扩大窗口。
我们知道,TCP首部中窗口字段长度是16位,因此最大的窗口大小为64K字节。虽然这对早期的网络是足够用的,但对于包含卫星信道的网络,传播时延和宽带都很大,要获得高吞吐量需要更大的窗口大小。
窗口扩大选项占3字节,其中有一个字节表示移位值S。新的窗口值等于TCP首部中的窗口位数从16增大到(16+S)。移位值允许使用的最大值是14,相当于窗口最大值增大到2 (16+14)-1=2 30-1。
窗口扩大选项可以在双方初始建立TCP连接时进行协商。如果连接的某一端实现了窗口扩大,当它不再需要扩大其窗口时,可发送S=0选项,使窗口大小回到16。
时间戳选项占10字节,其中最主要的字段是时间戳字段(4字节)和时间戳回送回答字段(4字节)。时间戳选项有以下两个概念:
第一、 用来计算往返时间RTT。发送方在发送报文段时把当前时钟的时间值放入时间戳字段,接收方在确认该报文段时把时间戳字段复制到时间戳回送回答字段。因此,发送方在收到确认报文后,可以准确地计算出RTT来。
第二、 用于处理TCP序号超过2 32 的情况,这又称为防止序号绕回PAWS。我们知道,TCP报文段的序号只有32位,而每增加2 32 个序号就会重复使用原来用过的序号。当使用高速网络时,在一次TCP连接的数据传送中序号很可能被重复使用。例如,当使用15Mbit/s的速度发送报文段时,序号重复要6小时以上。但若用25Gbit/s的速率发送报文段,则不到14秒钟序号就会重复。为了使接收方能够把新的报文段和迟到很久的报文段区分开,则可以在报文段中加上这种时间戳。
从 功能 和 性能 的角度去理解
三次握手建立连接
第一次:
C 向 S 发送一个 建立连接 的请求。此过程中携带一些报文属性信息,这些信息,存在于报文首部,有初始化用的信息,比如,有用于认证的信息。
初始化信息:如报文序列号、
SYN: TCP在数据通信之前,通过TCP首部发送的一个 SYN 标志位,作为建立连接的请求等待接收方确认应答。如果 S 发来确认应答,则认为可以进行数据通信,否则,就不能进行通信。
TCP规定:SYN=1 的报文段不能携带数据,但是要 消耗掉一个序号 :seq=x。
这个时候 C 进入 SYN-SENT ( 同步已发送 )状态。
第二次:
S 收到 C 请求后,如果同意建立连接,则向 C 返回确认信息:将 SYN 、 ACK 都置 1 ,确认号为 ack=seq+1 (seq来自客户端),并携带自己的 初始化,同时用于认证的信息S 。
同理: SYN=1 的报文段不能携带数据,但是要 消耗掉一个序号 :seq=y。
这个时候 S 进入 SYN-RCVD ( 同步已接收 )状态。 C 收到 S 返回的确认信息后,进入 ESTABLISHED (已建立连接)的状态,
第三次:
C 收到 S 返回的确认信息后,向 S 再一次发送确认报文。 ACK 置为 1 ,确认号 ack=seq+1 (seq来自 S ),自己的 seq=x+1 。
TCP规定: ACK报文可以携带数据。但是,如果不携带数据,则不消耗序号,这时,下一数据报文段的序号仍是 seq=x+1 。 服务器 收到 客户端 返回的确认信息后,也进入 ESTABLISHED (已建立连接)的状态,
从功能角度去考虑前两次握手,从性能的角度去理解为什么需要第三次握手。
有第三次,是考虑到一种错误情况: 假设 C 发了一请求建立连接的报文,长时间未收到 S 的确认报文,则 C 会重发,这个时候 S 与之建立连接、完成数据通信、关闭了连接,这个时候 C 第一发出的请求建立连接的报文到达了 S , S 则会等待 C 发送数据,实际上 C 已经 CLOSED 了, S 就一直在这等待,浪费资源,
确切地说,应该是至少四次数据交互才能实现一个连接的彻底关闭。关闭连接,需要四个报文来指示关闭。
TCP是全双工通信的,所以在一端发送数据完毕后,还具有接收另一端的数据的能力,这就所谓的半关闭。
四次挥手
举个例子 :如果 C 的数据已经发送完毕, C 是不能立即关闭的,因为建立连接的通信双方是平等的。
C 首先告诉 S :“数据发送完毕“,这个消息在TCP报文的首部由 FIN 来标识,让 S 知道 C 是准备断开连接了。这是第一次挥手。
S 收到 C 发来的 FIN 标识的报文后,要给 C 端恢复一个 确认FIN 的消息,告诉 C 说,知道你的数据发完了。这是第二次挥手。
这个时候,如果 S 端的数据也发送完毕了,就给 C 发一个 FIN=1 报文。这是第三次挥手。
C 收到 S 发来的 FIN 标识的报文后,要给 S 端恢复一个 确认FIN 的消息,告诉 C 说,知道你的数据发完了。这是第四次挥手。
然后就彻底断开连接了。
TCP的状态变迁图
说明:
这里是TCP连接的三握手的报文交互,其中协议各个字段的含义如下:
tos表示服务类型,4bit的tos分别表示最小时延,最大吞吐量,最高可靠性,最小费用。这里都是0,表示一般服务,其余4bit废用,置0
TTL(time - to - live)生存时间字段设置了数据报可以经过的最多路由器数。它指定了数据报的生存时间。TTL的初始值由源主机设置(通常为32或64),一旦经过一个处理它的路由器,它的值就减去1。当该字段的值为0时,数据报就被丢弃,并发送ICMP报文通知源主机。
id 对应IP报文头的Identification,用于IP分片重组。
offset 也用于IP分片重组,表示相对于原始未分片的报文的位置。
flags MF表示有更多分片,DF表示不分片,这里是DF,未使用分片,所以id和offset的值都可以忽略。
proto 表示协议,可以是TCP,UDP等,这里是TCP。
length 总长度字段,是指整个I P数据报的长度(至于首部长度这里没有给出,首部长度给出首部中32 bit字的数目。需要这个值是因为任选字段的长度是可变的。这个字段占4 bit,因此TCP最多有60字节的首部。然而没有任选字段,正常的长度是20字节)。
12700160534 > 1270016888表示数据是从IP为127001端口为60534发送到IP为127001端口为6888。分别对应的IP报文头的源地址和目的地址,以及TCP报文头的源端口和目的端口。
S 当建立一个新的连接时,SYN标志变1。序号字段包含由这个主机选择的该连接的初始序号ISN(Initial Sequence Number)。该主机要发送数据的第一个字节序号为这个ISN加1,因为SYN标志消耗了一个序号,这里客户端的ISN是2584692379,服务端的ISN是2589673026。
chksum 16位检验和,这里有IP首部检验和和TCP报文段(包括TCP首部和数据)检验和,具体是哪个检验和不详。
2584692379:2584692379(0)表示,第一个2584692379表示TCP报文段的序列号,(0)表示数据长度是0,即没有数据,第二个2584692379是第一个2584692379+数据长度 计算出来的。TCP是可靠连接,三握手的最大目的是为了初始化双方的ISN。假设客户端连接服务端,发送数据,刚好网络比较慢,在传输过程中,客户端和服务端已经都重启了,重新建立连接发送数据,发送过程中,服务端收到已经之前客户端的数据,发现ISN非法,就会抛弃这个包,不会对现有的服务造成影响。这个只是ISN的一方面的作用。
win TCP窗口大小,通知对方,发送方最多还可以接收的数据量,用于TCP的拥塞控制。第一个报文表示客户端通知服务端,客户端可以接受的数据的缓存区最大是32792个字节。服务端通知客户端,服务端最多可以接受的缓存区最大是32768,这个窗口大小在一方接受数据,却没有read的时候,窗口会逐渐减小,直至为0,最后对方不可以发送任何数据(如果要做该测试,需要发送的数据量大概接近65535,因为窗口的缓存区也会在剩余容量减小时,自动增加总共容量,直到总共容量接近65535,接下来就会看到win越来越小,直至0)。
ack TCP是可靠连接,所以收到发送方的数据,接受方就会发送ack确认,告诉发送方,接受方已经接收到数据,否则,发送方认为数据没有发送成功,重复发送数据。第二个包有ack 2584692380,其中2584692380是第一个报文包的2584692379:2584692379(0)的第二个2584692379+1的值。
<mss 16396,sackOK,timestamp 10962859 0,nop,wscale 6>这里表示IP报文头的可选字段,mss是最小最大分段大小,这里是16396,表示一个TCP报文段发送的数据最大可以是16396个字节,可能是lo设备的关系,这个mss很大,一般都是MTU 1500 个字节 - IP数据报文头20个字节- TCP报文头20个字节 = 1460个字节。wscale是TCP窗口扩大选项的窗口扩大因子,用于扩大TCP通告窗口,使TCP的窗口定义从16bit增加为32bit。这里的wscale是6,那么实际窗口是513左移6位,既513 X 64 = 32832,这个选项只在一个SYN报文中有意义。其他选项不详,具体参考RFC。
发送时延=数据长度/信道带宽=655358bit/1Gb/s=05242810-3s=052428ms;
传播往返时延=210=20ms (发送数据和接收确认);
故每发送一个窗口大小的流量需要,
总时延 = 发送时延 + 传播往返时延 = 052428+20=2052428ms。
故每秒钟可以产生1000/2052428个窗口,
因此最大数据吞吐量=655368(1000/2052428)=25544769bit/s=255Mb/s
信道的利用率 = 255Mb/s÷1000Mb/s≈255%
注释:1Kb/s=10^3b/s,1Mb/s=10^6b/s,1Gb/s=10^9b/s。
扩展资料一个数字脉冲称为一个码元,我们用码元速率表示单位时间内信号波形的变换次数,即单位时间内通过信道传输的码元个数。若信号码元宽度为T秒,则码元速率B=1/T。码元速率的单位叫波特(Baud),所以码元速率也叫波特率。
一个数字脉冲称为一个码元,我们用码元速率表示单位时间内信号波形的变换次数,即单位时间内通过信道传输的码元个数。若信号码元宽度为T秒,则码元速率B=1/T。码元速率的单位叫波特(Baud),所以码元速率也叫波特率。
早在1924年,贝尔实验室的研究员亨利·尼奎斯特就推导出了有限带宽无噪声信道的极限波特率,称为尼奎斯特定理。若信道带宽为W,则尼奎斯特定理指出最大码元速率为B=2W(Baud)尼奎斯特定理指定的信道容量也叫尼奎斯特极限,这是由信道的物理特性决定的。超过尼奎斯特极限传送脉冲信号是不可能的,所以要进一步提高波特率必须改善信道带宽。
拥塞控制。接收窗口的大小,体现了接收端对发送端施加的流量控制,而拥塞窗口的大小则是整个互联网负载情况对发送端施加的拥塞控制。拥塞控制是一种用来调整传输控制协议(TCP)连接单次发送的分组数量(单次发送量,在英文文献和程序代码中常叫做cwnd)的算法。
以上就是关于TCP 的优化全部的内容,包括:TCP 的优化、TCP流量控制、centos内核参数网速等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)