什么是 TCP ?
TCP 是面向链接的、可靠的、基于字节流的传输层通讯协议。javascript
什么是 TCP 链接?
简单来讲就是,用于保证可靠性和流量控制维护的某些状态信息,这些信息的组合,包括Socket、序列号和窗口大小称为链接。html
因此咱们能够知道,创建一个 TCP 链接是须要客户端与服务器端达成上述三个信息的共识。java
如何肯定惟一的一个 TCP 链接呢?
TCP 四元组能够肯定惟一的一个链接,四元组包括以下:linux
源地址和目标地址的字段(32位)是在 IP 头部中,做用是经过 IP 协议发送报文给对方主机。面试
源端口和目标端口的字段(16位)是在 TCP 头部中,做用是告诉 TCP 协议应该把报文发给哪一个进程。算法
字段名称 | 长度(比特) | 含 义 |
---|---|---|
源端口号 | 16 | 发送网络包的程序的端口号 |
目标端口号 | 16 | 接收网络包的程序的端口号 |
序号(Sequence Number) | 32 | Sequence Number是包的序号,用来解决网络包乱序(reordering)问题。 |
确认序号(Acknowledgement Number) | 32 | Acknowledgement Number就是ACK——用于确认收到,用来解决不丢包的问题。 |
首部长度 | 4 | 表示数据部分的起始位置,也能够认为表示头部的长度 |
保留 | 6 | 该字段为保留,如今未使用 |
控制位 | 6 | 该字段中的每一个比特分别表示如下通讯控制含义。<br/>URG:为1表示高优先级数据包,紧急指针字段有效。<br/>ACK:为1表示确认序号字段有效,通常表示数据已被接收方收到。<br/>PSH:为1表示是带有PUSH标志的数据,指示接收方应该尽快将这个报文段交给应用层而不用等待缓冲区装满。<br/>RST:为1表示出现严重差错。可能须要重现建立TCP链接。还能够用于拒绝非法的报文段和拒绝链接请求。<br/>SYN:为1表示这是链接请求或是链接接受请求,用于建立链接和使顺序号同步。<br/>FIN:为1表示发送方没有数据要传输了,要求释放链接。 |
窗口大小 | 16 | 接收方告知发送方窗口大小(即无需等待确承认一块儿发送的数据量) |
校验和 | 16 | 用来检查是否出现错误 |
紧急指针 | 16 | 表示应紧急处理的数据位置 |
选项 | 可变长度 | 除了上面的固定头部字段以外,还能够添加可选字段,但除了链接操做以外,不多使用可选字段 |
第一个报文—— SYN 报文shell
client_isn
,在这里是seq = x
),将此序号置于 TCP 头字段的「序号」字段中,同时把 SYN
标志位置为 1
,表示 SYN
报文。接着把第一个 SYN 报文发送给服务端,表示向服务端发起链接,该报文不包含应用层数据,以后客户端处于 SYN-SENT
状态。第二个报文 —— SYN + ACK 报文浏览器
SYN
报文后,首先服务端也随机初始化本身的序号(server_isn
,在这里是seq = y
),将此序号填入 TCP 头字段的「序号」字段中,其次把 TCP 头字段的「确认序号」字段填入 client_isn + 1
, 接着把 SYN
和 ACK
标志位置为 1
。最后把该报文发给客户端,该报文也不包含应用层数据,以后服务端处于 SYN-RCVD
状态。第三个报文 —— ACK 报文缓存
ACK
标志位置为 1
,其次「确认序号」字段填入 server_isn + 1
,最后把报文发送给服务端,此次报文能够携带客户到服务器的数据,以后客户端处于 ESTABLISHED
状态。ESTABLISHED
状态。注意:安全
咱们看到有两个中间状态,syn_sent 和 syn_rcvd,这两个状态叫着「半打开」状态,就是向对方发送了,可是还没来得及看到对方的回应。
syn_sent 是主动打开方的「半打开」状态,syn_rcvd 是被动打开方的「半打开」状态。客户端是主动打开方,服务器是被动打开方。
FIN
标志位被置为 1
的报文,也即 FIN
报文,以后客户端进入 FIN_WAIT_1
状态。ACK
应答报文,接着服务端进入 CLOSED_WAIT
状态。ACK
应答报文后,以后进入 FIN_WAIT_2
状态。FIN
报文,以后服务端进入 LAST_ACK
状态。FIN
报文后,回一个 ACK
应答报文,以后进入 TIME_WAIT
状态。ACK
应答报文后,就进入了 CLOSED
状态,至此服务端已经完成链接的关闭。2MSL
(4分钟)时间后,自动进入 CLOSED
状态,至此客户端也完成链接的关闭。你能够看到,每一个方向都须要一个 FIN 和一个 ACK,所以一般被称为四次挥手。
这里一点须要注意是:主动关闭链接的,才有 TIME_WAIT 状态。
四次挥手也并不老是四次挥手,中间的两个动做有时候是能够合并一块儿进行的,这个时候就成了三次挥手,主动关闭方就会从fin_wait_1
状态直接进入到time_wait
状态,跳过了fin_wait_2
状态。
重传机制的一种方式,就是在发送数据时,设定一个定时器,当超过指定的时间后,没有收到对方的 ACK
确认应答报文,就会重发该数据。
TCP 会在如下两种状况发生超时重传:
TCP 还有另一种快速重传(Fast Retransmit)机制,它不以时间为驱动,而是以数据驱动重传。
在上图,发送方发出了 1,2,3,4,5 份数据:
快速重传机制只解决了一个问题,就是超时时间的问题,可是它依然面临着另一个问题。就是重传的时候,是重传以前的一个,仍是重传全部的问题。
SACK
( Selective Acknowledgment 选择性确认),这种方式须要在 TCP 头部「选项」字段里加一个 SACK
,它能够将缓存的地图发送给发送方,这样发送方就能够知道哪些数据收到了,哪些数据没收到,知道了这些信息,就能够只重传丢失的数据。
以下图,发送方收到了三次一样的 ACK 确认报文,因而就会触发快速重发机制,经过 SACK
信息发现只有 200~299
这段数据丢失,则重发时,就只选择了这个 TCP 段进行重复。
Duplicate SACK 又称 D-SACK
,其主要使用了 SACK 来告诉「发送方」有哪些数据被重复接收了。
D-SACK
。可见,D-SACK
有这么几个好处:
为解决这个问题,TCP 引入了窗口这个概念。即便在往返时间较长的状况下,它也不会下降网络通讯的效率。
那么有了窗口,就能够指定窗口大小,窗口大小就是指无需等待确认应答,而能够继续发送数据的最大值。
窗口的实现其实是操做系统开辟的一个缓存空间,发送方主机在等到确认应答返回以前,必须在缓冲区中保留已发送的数据。若是定期收到确认应答,此时数据就能够从缓存区清除。
假设窗口大小为 3
个 TCP 段,那么发送方就能够「连续发送」 3
个 TCP 段,而且中途如有 ACK 丢失,能够经过「下一个确认应答进行确认」。以下图:
只要发送方收到了 ACK 700 确认应答,就意味着 700 以前的全部数据「接收方」都收到了。这个模式就叫累计确认或者累计应答。
窗口大小由哪一方决定?
TCP 头里有一个字段叫 Window
,也就是窗口大小。
这个字段是接收端告诉发送端本身还有多少缓冲区能够接收数据。因而发送端就能够根据这个接收端的处理能力来发送数据,而不会致使接收端处理不过来。
因此,一般窗口的大小是由接收方的窗口大小来决定的。
发送方发送的数据大小不能超过接收方的窗口大小,不然接收方就没法正常接收到数据。
发送方的滑动窗口
咱们先来看看发送方的窗口,下图就是发送方缓存的数据,根据处理的状况分红四个部分,其中深蓝色方框是发送窗口,紫色方框是可用窗口:
在下图,当发送方把数据「所有」都一下发送出去后,可用窗口的大小就为 0 了,代表可用窗口耗尽,在没收到 ACK 确认以前是没法继续发送数据了。
在下图,当收到以前发送的数据 32~36
字节的 ACK 确认应答后,若是发送窗口的大小没有变化,则滑动窗口往右边移动 5 个字节,由于有 5 个字节的数据被应答确认,接下来 52~56
字节又变成了可用窗口,那么后续也就能够发送 52~56
这 5 个字节的数据了。
程序是如何表示发送方的四个部分的呢?
TCP 滑动窗口方案使用三个指针来跟踪在四个传输类别中的每个类别中的字节。其中两个指针是绝对指针(指特定的序列号),一个是相对指针(须要作偏移)。
SND.WND
:表示发送窗口的大小(大小是由接收方指定的);SND.UNA
:是一个绝对指针,它指向的是已发送但未收到确认的第一个字节的序列号,也就是 #2 的第一个字节;SND.NXT
:也是一个绝对指针,它指向未发送但可发送范围的第一个字节的序列号,也就是 #3 的第一个字节;SND.UNA
指针加上 SND.WND
大小的偏移量,就能够指向 #4 的第一个字节了。那么可用窗口大小的计算就能够是:
可用窗口大 = SND.WND -(SND.NXT - SND.UNA)
接收方的滑动窗口
接下来咱们看看接收方的窗口,接收窗口相对简单一些,根据处理的状况划分红三个部分:
其中三个接收部分,使用两个指针进行划分:
RCV.WND
:表示接收窗口的大小,它会通告给发送方。RCV.NXT
:是一个指针,它指向指望从发送方发送来的下一个数据字节的序列号,也就是 #3 的第一个字节。RCV.NXT
指针加上 RCV.WND
大小的偏移量,就能够指向 #4 的第一个字节了。接收窗口和发送窗口的大小是相等的吗?
并非彻底相等,接收窗口的大小是约等于发送窗口的大小的。
由于滑动窗口并非一成不变的。好比,当接收方的应用进程读取数据的速度很是快的话,这样的话接收窗口能够很快的就空缺出来。那么新的接收窗口大小,是经过 TCP 报文中的 Windows 字段来告诉发送方。那么这个传输过程是存在时延的,因此接收窗口和发送窗口是约等于的关系。
发送方不能无脑的发数据给接收方,要考虑接收方处理能力。
若是一直无脑的发数据给对方,但对方处理不过来,那么就会致使触发重发机制,从而致使网络流量的无故的浪费。
为了解决这种现象发生,TCP 提供一种机制可让「发送方」根据「接收方」的实际接收能力控制发送的数据量,这就是所谓的流量控制。
根据上图的流量控制,说明下每一个过程:
Usable
减小为 120 字节,同时 SND.NXT
指针也向右偏移 80 字节后,指向 321,这意味着下次发送数据的时候,序列号是 321。RCV.NXT
也就指向 321,这意味着客户端指望的下一个报文的序列号是 321,接着发送确认报文给服务端。RCV.NXT
也就指向 441,接着发送确认报文给服务端。SND.UNA
指针往右偏移后指向 321,因而可用窗口 Usable
增大到 80。SND.UNA
指针往右偏移后指向 441,因而可用窗口 Usable
增大到 200。SND.NXT
指向 601,因而可用窗口 Usable
减小到 40。RCV.NXT
也就是指向了 601,接着发送确认报文给服务端。SND.UNA
指针偏移了 160 后指向 601,可用窗口 Usable
也就增大至了 200。为何要有拥塞控制呀,不是有流量控制了吗?
前面的流量控制是避免「发送方」的数据填满「接收方」的缓存,可是并不知道网络的中发生了什么。
通常来讲,计算机网络都处在一个共享的环境。所以也有可能会由于其余主机之间的通讯使得网络拥堵。
在网络出现拥堵时,若是继续发送大量数据包,可能会致使数据包时延、丢失等,这时 TCP 就会重传数据,可是一重传就会致使网络的负担更重,因而会致使更大的延迟以及更多的丢包,这个状况就会进入恶性循环被不断地放大….
因此,TCP 不能忽略网络上发生的事,它被设计成一个无私的协议,当网络发送拥塞时,TCP 会自我牺牲,下降发送的数据量。
因而,就有了拥塞控制,控制的目的就是避免「发送方」的数据填满整个网络。
为了在「发送方」调节所要发送数据的量,定义了一个叫作「拥塞窗口」的概念。
什么是拥塞窗口?和发送窗口有什么关系呢?
拥塞窗口 cwnd是发送方维护的一个的状态变量,它会根据网络的拥塞程度动态变化的。
咱们在前面提到过发送窗口 swnd
和接收窗口 rwnd
是约等于的关系,那么因为加入了拥塞窗口的概念后,此时发送窗口的值是swnd = min(cwnd, rwnd),也就是拥塞窗口和接收窗口中的最小值。
拥塞窗口 cwnd
变化的规则:
cwnd
就会增大;cwnd
就减小;那么怎么知道当前网络是否出现了拥塞呢?
其实只要「发送方」没有在规定时间内接收到 ACK 应答报文,也就是发生了超时重传,就会认为网络出现了用拥塞。
拥塞控制有哪些控制算法?
拥塞控制主要是四个算法:
慢启动
TCP 在刚创建链接完成后,首先是有个慢启动的过程,这个慢启动的意思就是一点一点的提升发送数据包的数量,若是一上来就发大量的数据,这不是给网络添堵吗?
慢启动的算法记住一个规则就行:当发送方每收到一个 ACK,拥塞窗口 cwnd 的大小就会加 1。
这里假定拥塞窗口 cwnd
和发送窗口 swnd
相等,下面举个栗子:
cwnd = 1
,表示能够传一个 MSS
大小的数据。能够看出慢启动算法,发包的个数是指数性的增加。
那慢启动涨到何时是个头呢?
有一个叫慢启动门限 ssthresh
(slow start threshold)状态变量。
cwnd
< ssthresh
时,使用慢启动算法。cwnd
>= ssthresh
时,就会使用「拥塞避免算法」。拥塞避免
前面说道,当拥塞窗口 cwnd
「超过」慢启动门限 ssthresh
就会进入拥塞避免算法。
通常来讲 ssthresh
的大小是 65535
字节。
那么进入拥塞避免算法后,它的规则是:每当收到一个 ACK 时,cwnd 增长 1/cwnd。
接上前面的慢启动的栗子,现假定 ssthresh
为 8
:
MSS
大小的数据,变成了线性增加。因此,咱们能够发现,拥塞避免算法就是将本来慢启动算法的指数增加变成了线性增加,仍是增加阶段,可是增加速度缓慢了一些。
就这么一直增加着后,网络就会慢慢进入了拥塞的情况了,因而就会出现丢包现象,这时就须要对丢失的数据包进行重传。
当触发了重传机制,也就进入了「拥塞发生算法」。
拥塞发生
当网络出现拥塞,也就是会发生数据包重传,重传机制主要有两种:
这两种使用的拥塞发送算法是不一样的,接下来分别来讲说。
发生超时重传的拥塞发生算法
这个时候,ssthresh 和 cwnd 的值会发生变化:
ssthresh
设为 cwnd/2
,cwnd
重置为 1
接着,就从新开始慢启动,慢启动是会忽然减小数据流的。这真是一旦「超时重传」,立刻回到解放前。可是这种方式太激进了,反应也很强烈,会形成网络卡顿。
发生快速重传的拥塞发生算法
还有更好的方式,前面咱们讲过「快速重传算法」。当接收方发现丢了一个中间包的时候,发送三次前一个包的 ACK,因而发送端就会快速地重传,没必要等待超时再重传。
TCP 认为这种状况不严重,由于大部分没丢,只丢了一小部分,则 ssthresh
和 cwnd
变化以下:
cwnd = cwnd/2
,也就是设置为原来的一半;ssthresh = cwnd
;快速恢复
快速重传和快速恢复算法通常同时使用,快速恢复算法是认为,你还能收到 3 个重复 ACK 说明网络也不那么糟糕,因此没有必要像 RTO
超时那么强烈。
正如前面所说,进入快速恢复以前,cwnd
和 ssthresh
已被更新了:
cwnd = cwnd/2
,也就是设置为原来的一半;ssthresh = cwnd
;而后,进入快速恢复算法以下:
cwnd = ssthresh + 3
( 3 的意思是确认有 3 个数据包被收到了);也就是没有像「超时重传」一晚上回到解放前,而是还在比较高的值,后续呈线性增加。
拥塞算法示意图
为何是三次握手,不是两次?不是四次?
缘由一:避免历史链接
简单来讲,三次握手的 首要缘由是为了防止旧的重复链接初始化形成混乱。
客户端连续发送屡次 SYN
创建链接的报文,在网络拥堵状况下:
SYN + ACK
报文给客户端;RST
报文给服务端,表示停止这一次链接。若是是两次握手链接,就不能判断当前链接是不是历史链接,三次握手则能够在客户端(发送方)准备发送第三次报文时,客户端因有足够的上下文来判断当前链接是不是历史链接:
RST
报文,以此停止历史链接;ACK
报文,通讯双方就会成功创建链接;因此,TCP 使用三次握手创建链接的最主要缘由是防止历史链接初始化了链接。
缘由二:同步双方初始序号
TCP 协议的通讯双方, 都必须维护一个「序号」, 序列号是可靠传输的一个关键因素,它的做用:
可见,序号在 TCP 链接中占据着很是重要的做用,因此当客户端发送携带「初始序号」的 SYN
报文的时候,须要服务端回一个 ACK
应答报文,表示客户端的 SYN 报文已被服务端成功接收,那当服务端发送「初始序号」给客户端的时候,依然也要获得客户端的应答回应,这样一来一回,才能确保双方的初始序列号能被可靠的同步。
四次握手其实也可以可靠的同步双方的初始化序号,但因为第二步和第三步能够优化成一步,因此就成了「三次握手」。
而两次握手只保证了一方的初始序列号能被对方成功接收,没办法保证双方的初始序列号都能被确认接收。
缘由三:避免资源浪费
若是只有「两次握手」,当客户端的 SYN
请求链接在网络中阻塞,客户端没有接收到 ACK
报文,就会从新发送 SYN
,因为没有第三次握手,服务器不清楚客户端是否收到了本身发送的创建链接的 ACK
确认信号,因此每收到一个 SYN
就只能先主动创建一个链接,这会形成什么状况呢?
若是客户端的 SYN
阻塞了,重复发送屡次 SYN
报文,那么服务器在收到请求后就会创建多个冗余的无效连接,形成没必要要的资源浪费。
即两次握手会形成消息滞留状况下,服务器重复接受无用的链接请求 SYN
报文,而形成重复分配资源。
小结
TCP 创建链接时,经过三次握手能防止历史链接的创建,能减小双方没必要要的资源开销,能帮助双方同步初始化序列号。序列号可以保证数据包不重复、不丢弃和按序传输。
不使用「两次握手」和「四次握手」的缘由:
什么是 SYN 攻击?如何避免 SYN 攻击?
SYN 攻击
咱们都知道 TCP 链接创建是须要三次握手,假设攻击者短期伪造不一样 IP 地址的 SYN
报文,服务端每接收到一个 SYN
报文,就进入SYN_RCVD
状态,但服务端发送出去的 ACK + SYN
报文,没法获得未知 IP 主机的 ACK
应答,长此以往就会占满服务端的 SYN 接收队列(未链接队列),使得服务器不能为正经常使用户服务。
避免 SYN 攻击方式一
其中一种解决方式是经过修改 Linux 内核参数,控制队列大小和当队列满时应作什么处理。
当网卡接收数据包的速度大于内核处理的速度时,会有一个队列保存这些数据包。控制该队列的最大值以下参数:
net.core.netdev_max_backlog
SYN_RCVD 状态链接的最大个数:
net.ipv4.tcp_max_syn_backlog
超出处理能时,对新的 SYN 直接回报 RST,丢弃链接:
net.ipv4.tcp_abort_on_overflow
避免 SYN 攻击方式二
咱们先来看下 Linux 内核的 SYN
(未完成链接创建)队列与 Accpet
(已完成链接创建)队列是如何工做的?
正常流程:
accpet()
socket 接口,从「 Accept 队列」取出链接。应用程序过慢:
受到 SYN 攻击:
tcp_syncookies
的方式能够应对 SYN 攻击的方法:
net.ipv4.tcp_syncookies = 1
tcp_syncookies 应对 SYN 攻击
cookie
值,再以 SYN + ACK 中的「序列号」返回客户端;accpet()
socket 接口,从「 Accept 队列」取出的链接。为何挥手须要四次?
FIN
时,仅仅表示客户端再也不发送数据了可是还能接收数据。FIN
报文时,先回一个 ACK
应答报文,而服务端可能还有数据须要处理和发送,等服务端再也不发送数据时,才发送 FIN
报文给客户端来表示赞成如今关闭链接。从上面过程可知,服务端一般须要等待完成数据的发送和处理,因此服务端的 ACK
和 FIN
通常都会分开发送,从而比三次握手致使多了一次。
为何 TIME_WAIT 等待的时间是 2MSL?
MSL
是 Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。由于 TCP 报文基因而 IP 协议的,而 IP 头中有一个 TTL
字段,是 IP 数据报能够通过的最大路由数,每通过一个处理他的路由器此值就减 1,当此值为 0 则数据报将被丢弃,同时发送 ICMP 报文通知源主机。
MSL 与 TTL 的区别: MSL 的单位是时间,而 TTL 是通过路由跳数。因此 MSL 应该要大于等于 TTL 消耗为 0 的时间,以确保报文已被天然消亡。
TIME_WAIT 等待 2 倍的 MSL,比较合理的解释是: 网络中可能存在来自发送方的数据包,当这些发送方的数据包被接收方处理后又会向对方发送响应,因此一来一回须要等待 2 倍的时间。
好比若是被动关闭方没有收到断开链接的最后的 ACK 报文,就会触发超时重发 Fin 报文,另外一方接收到 FIN 后,会重发 ACK 给被动关闭方, 一来一去正好 2 个 MSL。
2MSL
的时间是从客户端接收到 FIN 后发送 ACK 开始计时的。若是在 TIME-WAIT 时间内,由于客户端的 ACK 没有传输到服务端,客户端又接收到了服务端重发的 FIN 报文,那么 2MSL 时间将从新计时。
在 Linux 系统里 2MSL
默认是 60
秒,那么一个 MSL
也就是 30
秒。Linux 系统停留在 TIME_WAIT 的时间为固定的 60 秒。
其定义在 Linux 内核代码里的名称为 TCP_TIMEWAIT_LEN:
#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT state, about 60 seconds */
若是要修改 TIME_WAIT 的时间长度,只能修改 Linux 内核代码里 TCP_TIMEWAIT_LEN 的值,并从新编译 Linux 内核。
为何须要 TIME_WAIT 状态?
主动发起关闭链接的一方,才会有 TIME-WAIT
状态。
须要 TIME-WAIT 状态,主要是两个缘由:
缘由一:防止旧链接的数据包
接收到历史数据的异常
SEQ = 301
报文,被网络延迟了。SEQ = 301
抵达了客户端,那么客户端是有可能正常接收这个过时的报文,这就会产生数据错乱等严重的问题。因此,TCP 就设计出了这么一个机制,通过 2MSL
这个时间,足以让两个方向上的数据包都被丢弃,使得原来链接的数据包在网络中都天然消失,再出现的数据包必定都是新创建链接所产生的。
缘由二:保证链接正确关闭
在 RFC 793 指出 TIME-WAIT 另外一个重要的做用是:
TIME-WAIT - represents waiting for enough time to pass to be sure the remote TCP received the acknowledgment of its connection termination request.
也就是说,TIME-WAIT 做用是等待足够的时间以确保最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭。
假设 TIME-WAIT 没有等待时间或时间太短,断开链接会形成什么问题呢?
ACK
报文若是在网络中被丢失了,此时若是客户端 TIME-WAIT
太短或没有,则就直接进入了 CLOSED
状态了,那么服务端则会一直处在 LASE_ACK
状态。SYN
请求报文后,服务端会发送 RST
报文给客户端,链接创建的过程就会被终止。若是 TIME-WAIT 等待足够长的状况就会遇到两种状况:
ACK
报文,则服务端正常关闭链接。ACK
报文时,则会重发 FIN
关闭链接报文并等待新的 ACK
报文。因此客户端在 TIME-WAIT
状态等待 2MSL
时间后,就能够保证双方的链接均可以正常的关闭。
若是已经创建了链接,可是客户端忽然出现故障了怎么办?
TCP 有一个机制是保活机制。这个机制的原理是这样的:
定义一个时间段,在这个时间段内,若是没有任何链接相关的活动,TCP 保活机制会开始做用,每隔一个时间间隔,发送一个探测报文,该探测报文包含的数据很是少,若是连续几个探测报文都没有获得响应,则认为当前的 TCP 链接已经死亡,系统内核将错误信息通知给上层应用程序。
在 Linux 内核能够有对应的参数能够设置保活时间、保活探测的次数、保活探测的时间间隔,如下都为默认值:
net.ipv4.tcp_keepalive_time=7200 net.ipv4.tcp_keepalive_intvl=75 net.ipv4.tcp_keepalive_probes=9
也就是说在 Linux 系统中,最少须要通过 2 小时 11 分 15 秒才能够发现一个「死亡」链接。
这个时间是有点长的,咱们也能够根据实际的需求,对以上的保活相关的参数进行设置。
若是开启了 TCP 保活,须要考虑如下几种状况:
第一种,对端程序是正常工做的。当 TCP 保活的探测报文发送给对端, 对端会正常响应,这样 TCP 保活时间会被重置,等待下一个 TCP 保活时间的到来。
第二种,对端程序崩溃并重启。当 TCP 保活的探测报文发送给对端后,对端是能够响应的,但因为没有该链接的有效信息,会产生一个 RST 报文,这样很快就会发现 TCP 链接已经被重置。
第三种,是对端程序崩溃,或对端因为其余缘由致使报文不可达。当 TCP 保活的探测报文发送给对端后,石沉大海,没有响应,连续几回,达到保活探测次数后,TCP 会报告该 TCP 链接已经死亡。
UDP 头部格式
UDP 和 TCP 有什么区别呢?
1. 链接
2. 服务对象
3. 可靠性
4. 拥塞控制、流量控制
5. 首部开销
20
个字节,若是使用了「选项」字段则会变长的。6. 传输方式
7. 分片不一样
UDP 和 TCP 应用场景
因为 TCP 是面向链接,能保证数据的可靠性交付,所以常常用于:
FTP
文件传输HTTP
/ HTTPS
因为 UDP 面向无链接,它能够随时发送数据,再加上UDP自己的处理既简单又高效,所以常常用于:
DNS
、SNMP
等IP 在 TCP/IP 参考模型中处于第三层,也就是网络层。
网络层的主要做用是:实现主机与主机之间的通讯,也叫点对点(end to end)通讯。
IPv4表示
IP 地址(IPv4 地址)由 32
位正整数来表示,IP 地址在计算机是以二进制的方式处理的。
而人类为了方便记忆采用了点分十进制的标记方式,也就是将 32 位 IP 地址以每 8 位为组,共分为 4
组,每组以「.
」隔开,再将每组转换成十进制。
互联网诞生之初,IP 地址显得很充裕,因而计算机科学家们设计了分类地址。
IP 地址分类成了 5 种类型,分别是 A 类、B 类、C 类、D 类、E 类。
上图中黄色部分为分类号,用以区分 IP 地址类别。
什么是 A、B、C 类地址?
其中对于 A、B、C 类主要分为两个部分,分别是网络号和主机号。
A、B、C 分类地址最大主机个数是如何计算的呢?
最大主机个数,就是要看主机号的位数,如 C 类地址的主机号占 8 位,那么 C 类地址的最大主机个数:
为何要减 2 呢?
由于在 IP 地址中,有两个 IP 是特殊的,分别是主机号全为 1 和 全为 0 地址。
所以,在分配过程当中,应该去掉这两种状况。
广播地址用于什么?
广播地址用于在同一个链路中相互链接的主机之间发送数据包。
当主机号全为 1 时,就表示该网络的广播地址。例如把 172.20.0.0/16
用二进制表示以下:
10101100.00010100.00000000.00000000
将这个地址的主机部分所有改成 1,则造成广播地址:
10101100.00010100.11111111.11111111
再将这个地址用十进制表示,则为 172.20.255.255
。
广播地址能够分为本地广播和直接广播两种。
什么是 D、E 类地址?
而 D 类和 E 类地址是没有主机号的,因此不可用于主机 IP,D 类常被用于多播,E 类是预留的分类,暂时未使用。
多播地址用于什么?
因为广播没法穿透路由,若想给其余网段发送一样的包,就可使用能够穿透路由的多播。
多播使用的 D 类地址,其前四位是 1110
就表示是多播地址,而剩下的 28 位是多播的组编号。
从 224.0.0.0 ~ 239.255.255.255 都是多播的可用范围,其划分为如下三类:
IP 分类的优势
无论是路由器仍是主机解析到一个 IP 地址时候,咱们判断其 IP 地址的首位是否为 0,为 0 则为 A 类地址,那么就能很快的找出网络地址和主机地址。
其他分类判断方式参考以下图:
因此,这种分类地址的优势就是简单明了、选路(基于网络地址)简单。
IP 分类的缺点
缺点一
同一网络下没有地址层次,好比一个公司里用了 B 类地址,可是可能须要根据生产环境、测试环境、开发环境来划分地址层次,而这种 IP 分类是没有地址层次划分的功能,因此这就缺乏地址的灵活性。
缺点二
A、B、C类有个尴尬处境,就是不能很好的与现实网络匹配。
IPv6 的亮点
IPv6 不只仅只是可分配的地址变多了,它还有很是多的亮点。
40
字节,去掉了包头校验和,简化了首部结构,减轻了路由器负荷,大大提升了传输的性能。IPv6 地址的标识方法
IPv4 地址长度共 32 位,是以每 8 位做为一组,并用点分十进制的表示方式。
IPv6 地址长度是 128 位,是以每 16 位做为一组,每组用冒号 「:」 隔开。
若是出现连续的 0 时还能够将这些 0 省略,并用两个冒号 「::」隔开。可是,一个 IP 地址中只容许出现一次两个连续的冒号。
IPv6 地址的结构
IPv6 相似 IPv4,也是经过 IP 地址的前几位标识 IP 地址的种类。
IPv6 的地址主要有如下类型地址:
IPv6 单播地址类型
对于一对一通讯的 IPv6 地址,主要划分了三类单播地址,每类地址的有效范围都不一样。
IPv6 相比 IPv4 的首部改进:
40
字节。DNS 域名解析,DNS 能够将域名网址自动转换为具体的 IP 地址。
域名解析的工做流程
浏览器首先看一下本身的缓存里有没有,若是没有就向操做系统的缓存要,尚未就检查本机域名解析文件 hosts
,若是仍是没有,就会 DNS 服务器进行查询,查询的过程以下:
在传输一个 IP 数据报的时候,肯定了源 IP 地址和目标 IP 地址后,就会经过主机「路由表」肯定 IP 数据包下一跳。然而,网络层的下一层是数据链路层,因此咱们还要知道「下一跳」的 MAC 地址。
因为主机的路由表中能够找到下一跳的 IP 地址,因此能够经过 ARP 协议,求得下一跳的 MAC 地址。
ARP 如何知道对方 MAC 地址的呢?
操做系统一般会把第一次经过 ARP 获取的 MAC 地址缓存起来,以便下次直接从缓存中找到对应 IP 地址的 MAC 地址。
不过,MAC 地址的缓存是有必定期限的,超过这个期限,缓存的内容将被清除。
参考:
35 张图解:被问千百遍的 TCP 三次握手和四次挥手面试题
[网络是怎么链接的]