TCP(传输控制协议)提供数据可靠传输,包括数据流传送、可靠性、有效流控、全双工操作和多路复用。通过面向连接、端到端和可靠的数据包发送。只支持1对1的通讯。
UDP(用户数据报协议)是一个简单的面向数据报的传输层协议。提供的是非面向连接的、不可靠的数据流传输。UDP不提供可靠性,也不提供报文到达确认、排序以及流量控制等功能。支持多对多的通讯。
另外,TCP建立连接需要三次握手,断开连接需要四次握手。
相信有网络基础的同学都已经掌握了,但对于那些参加面试的同学来说,掌握这些还不够。面试过程中常常遇到一些直击灵魂的问题?比如:
1 | 1. TCP为什么会是三次握手?二次或四次行不行? |
本文尝试按自己的理解来回答这些问题?
声明:本文不保证答案正确,仅代表个人理解,仅供交流参考。
先来看下正常的三次握手、四次挥手图解。
灵魂第一击
建立TCP连接为什么需要三次握手? 两次或四次是否可行
显然四次及以上都是可以的,但三次是达到可靠交互的最小握手次数。超过次数可以通过合并、剔除多余握手来解决。
那么两次可以吗?会存在什么问题呢?
从三次握手的交互来看,实质是相互交换Seq序列号并确认的过程。显然第一次和第二次握手不能省略(各自发送自己的序列号,同时服务端还对客户端的请求完成了确认)。
那么假设没有第三次握手,也就是客户端不对服务端的握手确认,这会导致什么情况呢?
书本回答是防止已失效连接请求报文段突然到达服务端而产生错误
“已失效的连接请求报文段” 的产生在这样一种情况下:client 发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达 server。本来这是一个早已失效的报文段。但 server 收到此失效的连接请求报文段后,就误认为是 client 再次发出的一个新的连接请求。于是就向 client 发出确认报文段,同意建立连接。假设不采用 “三次握手”,那么只要 server 发出确认,新的连接就建立了。由于现在 client 并没有发出建立连接的请求,因此不会理睬 server 的确认,也不会向 server 发送数据。但 server 却以为新的运输连接已经建立,并一直等待 client 发来数据。这样,server 的很多资源就白白浪费掉了。采用 “三次握手” 的办法可以防止上述现象发生。例如刚才那种情况,client 不会向 server 的确认发出确认。server 由于收不到确认,就知道 client 并没有要求建立连接。”
简单理解就是,客户端发送错误的连接请求,服务端也会确认并简历一个连接,而不需要客户端确认是否有效。
第二击
SYN洪水攻击的原理?如何预防?
SYN Flood是当前最流行的DoS(拒绝服务攻击)与DDoS(分布式拒绝服务攻击)的方式之一,它是利用TCP协议缺陷,发送大量伪造的TCP连接请求,从而使得被攻击方资源耗尽(CPU满负荷或内存不足)的攻击方式,最终导致系统或服务器宕机。
原理解析
要理解SYN洪水攻击还是不得不提建立连接时的三次握手。
客户端发起连接请求(SYN+Seq),服务端确认并发送序列号(ACK+Seq),这时形成一个半连接队列在服务端,当客户端第三次握手确认以后,会把连接从半连接队列里删除,移到全连接队列里。
对于半连接队列里的请求,服务端在规定的时间内收不到ACK,会重试发送ACK+Seq,在设定时间内得不到响应,连接删除。
那么问题来了,如果攻击者在设定时间内
发送大量连接请求,会导致短时间内服务端半连接队列溢出,正常的连接无法建立,服务端不停的重试确认,进而导致宕机。
预防
目前业界尚没有很好的监测和防御方法。
我们可以从攻击的原理方面着手思考:
- 增大半连接队列长度
- 减少服务端超时重试次数
- 合理设置超时时间
后验防范:
- 及时保存现场,提取目标IP,加入黑名单
第三击
Seq序号的作用是什么?初始值为什么要随机?
理解这个问题,我们先看下一个tcp包都包含哪些字段。
SYN表示建立连接,
FIN表示关闭连接,
ACK表示响应,
PSH表示有 DATA数据传输,
RST表示连接重置。
其中,ACK是可能与SYN,FIN等同时使用的,比如SYN和ACK可能同时为1,它表示的就是建立连接之后的响应
Seq序号的作用是什么? 我们知道TCP协议保证数据包按顺序接收,在不可靠信道中怎么来保证顺序到达呢,这就是Seq序列号的作用。
RFC793指出ISN(初始序列号)可以看作是一个32bit的计数器,每4ms加1,这样选择序号的目的在于防止在网络中被延迟的分组在以后被重复传输,而导致某个连接的一端对它作错误的判断。
TCP握手采用随机序列号(不完全随机,而是随着时间流逝而线性增长,到了2^32尽头再回滚),为的就是让攻击者更难以猜测sequence number,因为伪造的sequence number不在合法范围内,而被接收方丢弃,增加安全性。
第四问
TCP如何保证数据有序的?
显然,客户端和服务端是通过seq序号来排列数据包的顺序的。
主机每次发送数据时,TCP就给每个数据包分配一个序列号并且在一个特定的时间内等待接收主机对分配的这个序列号进行确认,如果发送主机在一个特定时间内没有收到接收主机的确认,则发送主机会重传此数据包。接收主机利用序列号对接收的数据进行确认,以便检测对方发送的数据是否有丢失或者乱序等,接收主机一旦收到已经顺序化的数据,它就将这些数据按正确的顺序重组成数据流并传递到高层进行处理。
具体步骤如下:
(1)为了保证数据包的可靠传递,发送方必须把已发送的数据包保留在缓冲区;
(2)并为每个已发送的数据包启动一个超时定时器;
(3)如在定时器超时之前收到了对方发来的应答信息(可能是对本包的应答,也可以是对本包后续包的应答),则释放该数据包占用的缓冲区;
(4)否则,重传该数据包,直到收到应答或重传次数超过规定的最大次数为止。
(5)接收方收到数据包后,先进行CRC循环冗余校验(Cyclic Redundancy Check, CRC)校验,如果正确则把数据交给上层协议,然后给发送方发送一个累计应答包,表明该数据已收到,如果接收方正好也有数据要发给发送方,应答包也可方在数据包中捎带过去。
第五问
time_wait出现在什么时候?为什么要等待2ML后结束?
由图可知,客户端接收到服务端发送的结束信号(FIN)并发送确认信号后进入time_wait状态。
那为什么客户端要等待2ML后才结束呢?能不能立即结束呢?
注:MSL是指Max Segment Lifetime,即数据包在网络中的最大生存时间。每种TCP协议的实现方法均要指定一个合适的MSL值,如RFC1122给出的建议值为2分钟,又如Berkeley体系的TCP实现通常选择30秒作为MSL值。这意味着TIME_WAIT的典型持续时间为1-4分钟。
个人认为等待2ML结束的原因有两个:
1、经过1个ML之后,服务端发送的所有的数据包都已经失效,避免错失延迟包
2、服务端在接收不到ACK时,会重新发送FIN,而客户端接收到这个重新发送的FIN的最大时间其实就是2ML(1次ACK到达服务端,1次服务端重试FIN到达客户端)。
##参考资料