TCP中几个用于提高传输效率的机制

1. Nagle算法与ACK延迟确认:

Nagle算法在发送端 开启,限制发送条件;
ACK延迟确认在 接收端 开启,二者的作用都是限制链路中小包的数量。

==> Nagle算法的规则:
(1)如果包长达到MSS,则允许发送;反之如果包长小于MSS,则不允许发送;
(2)如果该包含有FIN,则允许发送;
(3)在TCP连接上最多只能有一个 未被确认的 小数据包,在该分组的确认ACK到达之前,不能发送其他小的数据包;
(4)关闭Nagle算法:套接字开启 TCP_NODELAY 选项。

==> ACK延迟确认:
ACK延迟确认使接收端在收到数据报文后不会立即回复ACK,而是等待发现的数据报文,搭车发送。
ACK延迟确认的时长默认是 200 ms,如果超过 200 ms 都没有反向的业务数据要发送,则单独构造一个ACK确认报文返回发送端。
关闭ACK延迟确认:套接器开启 TCP_QUICKACK 选项。

==> Nagle算法和ACK延迟确认搭配使用,效果可能会不尽如人意:
当服务器有连续多个小包数据发送给客户端,在发送第一个小包之后,客户端收到,因为开启了ACK延迟确认,客户端不会立即回复ACK,需要等待 200 ms 超时,这时服务器因为开启了Nagle算法,同一时间只允许有一个未确认的小包在传,也不会发送下一个小包。
这会导致在等待的 200 ms 这段时间内,网络是处于空闲状态的,降低了传输效率。
当实际业务有这种场景时,允许关闭Nagle算法。

==> TCP_NODELAY 与 TCP_QUICKACK 的设置方法:

#include <sys/types.h>
#include <sys/socket.h>

int i = 1;
int setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(i));	//关闭Nagle算法
int setsockopt(sockfd, IPPROTO_TCP, TCP_QUICKACK, &i, sizeof(i));	//关闭QuickAck算法

2. 什么是“窗口关闭”?如何处理?

当接收端的缓冲区大小变为0时,就会发送 WindowSize=0 的窗口通告(通过ACK发送)来阻止发送端再发送数据,直到接收窗口不为0,接收端会发送新的窗口通告,通知发送端继续发送数据。(当接收缓冲区恢复大小不为0时,会 主动 通知发送端继续发送数据

这会引入一个潜在的风险:如果接收端用于通知发送端恢复数据传输的窗口通告ACK丢失,那么双方将陷入死锁。

解决方式是发送端周期性的发送 “窗口探测” 报文(Window Probe),让接收端回复当前的接收窗口大小。

窗口探测的次数一般为 3次,每次大约间隔 30~60 秒。如果3次后接收窗口仍为0,某些TCP实现将会发送RST来中断TCP连接。


3. 什么是“糊涂窗口综合症”?如何避免?

简言之,“糊涂窗口综合症”就是传输小字节的包(小于MSS),导致网络带宽资源的浪费。

当接收缓冲区过小时,通告窗口的大小(awnd)也会很小,此时如果发送数据,会导致TCP开销过大(TCP头长占 20~60 字节,而真正的TCP数据可能只有几个字节)。

为避免浪费带宽资源,应避免发送小包数据,具体做法有两种:
(1)接收端:当接收窗口小于 “min(MSS, 缓存空间/2)” 二者中的较小值时,就发送窗口通告 WindowSize=0,阻止发送端继续发送数据;
(2)发送端:Nagle算法,满足条件才发送。


4. 设置“MSS”的作用是什么?

MSS = Maximum Segment Size,是去除 IP头和TCP头之后的报文最大长度限制。

如果一个TCP包的长度过大,会被分成多个IP分片,由于IP层没有重传功能,全依靠TCP层的重传,当某个IP分片丢失时,会导致整个TCP包(多个IP分片)都需要重传,效率低。

使用MSS对TCP包长进行限制(小于IP包长)的目的在于当发生IP层丢包时只需要重传一个TCP层的分片,而不用重传所有分片。


5. 为什么在有TCP保证可靠传输的情况下,还需要UDP协议?

(1)管理连接的开销:
TCP保证可靠传输的前提条件是建立一对一的连接,每一个TCP连接的正常建立和关闭都需要至少7个报文段(三次握手、四次挥手)的基本开销。
因此 当需要交换少量数据时,一些应用程序更愿意选择在发送和接收数据之前不需要建立连接的UDP协议(此时需要应用程序自己来处理数据校验、重传、流量控制和拥塞管理等);

(2)首部开销:
UDP的头长只有8个字节,TCP的头长在没有OPTION选项字段时是20字节,最长为60个字节;

(3)服务对象:
TCP是一对一的连接,UDP既可以是一对一的传输,也可以是一对多、多对多的传输,支持广播;

(4)传输速率:
TCP因为有流量控制、拥塞控制等算法,会优先保证传输的可靠性,不会最大限度的占满带宽资源。某些下载软件(例如迅雷)会使用UDP传输,这就是为什么当局域网中的某个用户使用下载软件时其他用户几乎无法正常上网的原因。


6. Linux内核通过TCB来管理TCP连接:

fd <—> tcb

TCB = Tcp Control Block,TCP控制块。 它的存在一直伴随着TCP连接的生命周期,只要连接存在,TCB就一直存在。

TCP的11种连接状态(相当于是状态机)、TCP五元组信息(源IP、目的IP、源端口、目的端口、协议类型)、TCP连接对应的发送和接收缓冲区状态 等信息,全部都存储在TCB中。

每个TCB对应一个套接字描述字fd,内核负责维护TCB,将fd提供给应用程序调用,当应用程序调用各种socket编程API时(如accept、connect、send、read等),就可以通过fd找到对应的TCB,进而对TCP连接进行操作。


7. TCP保活机制:

当TCP连接长时间无活动时,TCP会启动保活机制,用于探测对端的连接是否还在,如果对端的实例已经被释放(例如应用程序宕掉,端口无人监听,内核协议栈会回复RST) 或 报文没有得到响应(例如对端主机不可达),本端TCP在连续几次探测无果后会将连接关闭。

net.ipv4.tcp_keepalive_time = 7200		//表示保活时间为7200秒(2小时),超过这个时间的连接没有任何活动,则会启动保活机制
net.ipv4.tcp_keepalive_intvl = 75		//表示每次探测间隔75秒
net.ipv4.tcp_keepalive_probes = 9		//表示如果检测9次无响应,则判定对方不可达,中断连接

tcp_keepalive_time + (tcp_keepalive_intvl * tcp_keepalive_probes) = 7200 + 75 * 9 = 7875秒

也就说,在Linux系统中,需要经过 2小时11分15秒 才会发现一个无活动连接。


8. shutdown 与 close 的区别:

#include <sys/socket.h>
int shutdown(int sockfd, int how);	//SHUT_RD, SHUT_WR, SHUT_RDWR

#include <unistd.h>
int close(int fd);

(1)最明显的区别:close是全关闭,关闭一个连接的两个传输方向,应用程序调用close后,将套接字从内存中清除,不会再从这个fd对应的TCP连接上读取或发送数据;
shutdown是半关闭,可以指定关闭连接的读或写中的某一个方向,关闭后fd依然存在,仍然可以被应用程序的socket API函数继续调用。

(2)close是对套接字描述符fd的引用计数减1,并不是真正的关闭TCP连接,需要等到fd的引用计数降为0才会真正关闭(例如父子进程使用同一套接字fd的情况);shutdown会立即发送一个FIN到对端。

注:shutdown中 SHUT_RD 不会发出FIN,SHUT_WR和SHUT_RDWR会发出FIN。
SHUT_RD 只是用户进程通知内核我不再从这条连接上读取数据了,对端可以通过TCP发送数据过来,但是数据到达内核的TCP接收缓冲区后,不会通知已调用SHUT_RD的应用进程;
SHUT_WR 表示用户进程通知内核我不会再向这条连接上写入数据,此时内核会发送FIN通知对端,本连接将不会写入数据,关闭写方向。)


9. 使用 tcpdump 抓取TCP报文进行分析的方法:

tcpdump -i eth1 -n and tcp and src port 65535 and src host 127.0.0.1
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值