简介
TCP协议又叫传输控制协议(Transport Control Protocal),是面向连接的,可靠的字节流服务。它的连接是虚连接,连接的端点是套接字(SOCKET)。它的可靠性体现在:3次握手建立连接,滑动窗口机制,一定的拥塞避免算法,流量控制,以及一定的超时重传机制。基于TCP的协议有HTTP、FTP、SMTP、TELNET、SSH、MQTT等。
TCP的服务与缓存
服务
谈TCP服务之前先说一下计时器,很多服务需要计时器的支持。
- 2MSL计时器测量一个连接处于TIME_WAIT状态的时间,四次挥手(连接释放)时有用到。
- 重传计时器使用于当希望收到另一端的确认。超时重传、拥塞避免时有用到。
- 坚持计时器使窗口大小信息保持不断流动,即接收端发送了接收窗口为0的报文后启动。流量控制时有用到。
- 保活计时器可检测到一个空闲连接的另一端何时崩溃或重启。
接下来是TCP提供的服务:
数据块分割:应用数据被分割成TCP认为最适合发送的数据块,由TCP传递给IP的信息单位称为报文段或段(segment)。
重新排序:既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。如果必要,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。
全双工(Full Duplex)通信:又称为双向同时通信,即通信的双方可以同时发送和接收信息的信息交互方式。
可靠传输:通过校验和、序号、确认与重传进行可靠的传输。
流量控制:通过滑动窗口算法,设置接收窗口大小来进行流量控制。
拥塞控制:通过慢开始&拥塞避免、快重传&快恢复算法进行拥塞控制。
不提供广播或多播的服务。
缓存
发送缓存:准备发送的数据和已发送但未收到确认的数据
发送缓存图解
图中红色部分为已发送但未收到确认的数据,发送缓存中的其余部分为准备发送的数据。
接收缓存:按序到达但未接受应用程序读取的数据和不按序到达的数据
接收缓存图解
图中接收缓存中标识“已收到”的表示按序到达但未接受应用程序读取的数据,接收窗口中的红色部分是不按序到达的数据。
TCP头部
TCP首部格式
- 源端口和目的端口:各占 2 字节。端口是传输层与应用层的服务接口.传输层的复用和分用功能都要通过端口才能实现
- 序号seq:占4字节。数据中首个字节在发送缓存中的序号。
- 确认序号ack:占4字节。为N时表明序号N-1及之前的报文段都已经收到,期待接收序号为N的报文段。
- 首部长度/数据偏移: 占 4 位。它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远.“数据偏移”的单位是 32 位字(以 4 字节为计算单位)。
- 紧急位URG: 为1时,紧急指针有效,紧急数据优先级更高,优先发送。
- 确认位ACK: 为1时,确认序号ack有效,连接建立后,传送的报文段都必须把ACK置为1。
- 推送位PSH: 为1时,接收方应该尽快将这个报文段交给应用层,不用等缓存填满,优先级更高,报文段优先交给应用层。
- 复位RST: 为1时,表明TCP连接中出现严重差错,需要释放连接后,重建连接。
- 同步位SYN: 为1时,用来发起/确认一个连接。
- 终止位FIN: 为1时,表明发端完成发送任务,要求释放连接。
- 窗口:接收窗口,即允许对方发送的数据量。
- 检验和:检验首部+数据
- 紧急指针:URG为1时有效,指出本报文段中紧急数据的字节数(从数据的第一个字节开始)。
- 选项:最大报文段长度MSS(Maximum Segment Size):发送方告诉接收方,自身缓存所能接收的报文段的数据字段的最大长度是 MSS 个字节。
窗口扩大:占 3 字节,其中有一个字节表示移位值 S.新的窗口值等于TCP 首部中的窗口位数增大到(16 + S),相当于把窗口值向左移动 S 位后获得实际的窗口大小
时间戳:占10 字节,其中最主要的字段时间戳值字段(4字节)和时间戳回送回答字段(4字节)
选择确认:接收方收到了和前面的字节流不连续的两字节。如果这些字节的序号都在接收窗口之内,那么接收方就先收下这些数据,但要把这些信息准确地告诉发送方,使发送方不要再重复发送这些已收到的数据。
- 填充:这是为了使整个首部长度是 4 字节的整数倍。
TCP的建立与终止
TCP连接的建立采用客户/服务器方式,主动发起连接建立的应用进程叫做客户,而被动等待连接建立的应用进程叫服务器。
TCP连接四元组(sip,sport,dip,dport),源ip、源端口号、目的ip、目的端口号。
三次握手
TCP三次握手
客户端发送连接请求报文段,无应用层数据。同步位SYN=1,表示请求连接。序号seq=x(随机)。确认序号无效,ACK=0,因为客户端未收到服务器端的报文段。
- 服务器为该TCP连接分配缓存和变量,向客户端返回确认报文段,允许连接,无应用层数据。同步位SYN=1,表示确认连接。序号seq=y(随机),确认位ACK=1,确认序号有效,确认序号ack=x+1,即x+1之前的已经收到,期待接收x+1开始的报文段。
- 客户端为该TCP连接分配缓存和变量,并向服务器端返回确认报文段,可以携带数据。同步位SYN=0,表示连接建立完毕,以后的也是0。序号seq=x+1。确认位ACK=1,确认序号ack=y+1,即y+1之前的已经收到,期待接收y+1开始的报文段。
CLOSED: 表示初始关闭状态。
LISTEN(服务器): 这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。
SYN-SENT: 这个状态与SYN-RCVD呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN-SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN-SENT状态表示客户端已发送SYN报文。
SYN-RCVD(服务器): 这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。
ESTABLISHED:这个容易理解了,表示连接已经建立了,可以发送数据。
SYN洪泛攻击:攻击者向服务器发送大量TCP连接请求,服务器确认后,攻击者不确认,造成服务器处于半连接状态,消耗了过多的资源(CPU、内存等),造成死机等问题,无法为正常用户提供服务。可使用SYN Cookie进行防御。
四次挥手
客户端和服务器端都可以终止该连接,连接结束后,主机中的资源被释放。
以客户端主动终止连接为例。
TCP四次挥手
- 客户端发送连接释放报文段,停止发送数据。结束位FIN=1,表明要释放报文段,序号seq=u,假设上一个报文段序号为u-1。
- 服务器端回复一个确认报文段,客户到服务器这个方向的连接就释放了——半关闭状态。确认位ACK=1,序号seq=v,假设上一个报文段序号为v-1,确认序号ack=u+1。
- 服务器端发完数据,就发出连接释放报文段,主动关闭TCP连接。结束位FIN=1,确认位ACK=1,序号seq=w(服务器端上次发送的数据序号为v~w-1),确认序号ack=u+1(因为客户端未发送数据)。
- 客户端回复一个确认报文段。确认位ACK=1,序号seq=u+1,确认序号ack=w+1。
**ESTABLISHED:**建立连接成功,通信中。
CLOSE-WAIT: 表示被动关闭一方在等待关闭。当主动关闭连接的一方关闭SOCKET后发送FIN报文给被动关闭一方,被动关闭一方回应一个ACK报文给对方,此时被动关闭一方则进入到CLOSE-WAIT状态
FIN-WAIT-1:是当Socket在已经连接的状态时**主动关闭连接,**向对方发送了FIN报文,此时该Socket进入到FIN-WAIT-1状态。而当对方回应ACK报文后,则进入到FIN-WAIT-2状态
FIN-WAIT-2:表示半连接,挥了两次手的状态等待对方的Fin报文
TIM-WAIT:TCP协议中主动关闭连接的一方要处于TIME-WAIT状态,等待两个MSL(maximum segment lifetime)的时间后才能回到CLOSED状态,在TIME-WAIT期间仍然不能再次监听同样的server端口。
LAST-ACK: 被动关闭一方在发送FIN报 文后,最后等待对方的ACK报文。当收到ACK报文后进入CLOSED状态。
CLOSED:已经完全关闭.
服务器端收到确认报文段后关闭TCP连接。客户端等待两倍的MSL(Maximum Segment Lifetime,报文段最长寿命)时间后关闭连接,因为如果服务器端没有收到客户端回复的确认报文段会再次发出连接释放报文段,2MSL后没有收到服务器端再次发出的连接释放报文段,说明服务器端已关闭。
例题
[例题]主机甲与主机乙之间已建立一个TCP连接,主机甲向主机乙发送了两个连续的TCP段,分别包含300字节和500字节的有效载荷,第一个段的序列号为200,主机乙正确接收到两个段后,发送给主机甲的确认序列号是
A.500 B.700 C.800 D.1000
[解析]确认序号即期待的下一个报文段的开始字节,由于主机乙正确接收了两个段,所以乙收到了200~999(200+800-1)字节,期待第1000字节,所以选择D选项。
有限状态机
TCP有限状态机
粗实线为客户端三次握手与四次挥手的状态转移,粗虚线为服务器端三次握手与四次挥手的状态转移。
可靠传输
校验
增加伪首部
滑动窗口
以字节为单位的滑动窗口,大小可变。
接收窗口rwnd(recevier window):接收方根据接收缓存设置的值通知发送方,反映接收方容量。
拥塞窗口cwnd(congestion window):发送方根据自己估算的网络拥塞程度而设置的窗口值,反应网络当前容量。初始值IW根据SMSS(SENDER MAXIMUM SEGMENT SIZE,发送方最大报文段大小,不包含TCP头部)来设定。
发送窗口 = Min{接收窗口rwnd,拥塞窗口cwnd}
确认与重传
累计确认与超时重传
超时重传:TCP发送方在规定的时间(重传时间,使用重传计时器)内没有收到确认就要重传已发送的报文段。【重传时间:采用自适应算法,动态改变重传时间RTTs(加权平均往返时间)。RTT(round-trip time)为数据完全发送完(交给发送方IP层)到收到确认信号的时间。】
累计确认:收到多个确认一次。接收方“痴心不改”,例如,收到序号1、2、3、6的报文段,到了时间会发送确认序号ack=4的报文段,即使后续再收到了7、5,也依然会通知发送方“小老弟,我还是想要序号为4的报文段”。
超时重传解决的是传输可靠性问题,累计确认是为了更快速的传输。
冗余确认与快速重传
冗余确认:TCP接收方已经发送过的确认报文段。由于收到了比确认报文段所期待的报文段序号更大的报文段,而未收到确认报文段所期待的报文段,则再次发送确认报文段。如前面的序号4。【冗余确认是原因可能是乱序到达和丢包,两次的话可能是乱序到达造成的,三次的话绝大部分是丢包了,需要快速重传。】
快速重传:TCP发送方在未达到重传时间时收到接收方的冗余确认(三个重复的)就要重传已发送的报文段。
流量控制
目的:接收方希望发送方发慢一点,好来得及接收。
方法:利用滑动窗口机制实现流量控制。
在通信过程中,接收方根据自己接收缓存的大小,动态地调整发送方的发送窗口大小,即接收窗口rwnd(接收方设置确认报文段的窗口字段来将rwnd通知给发送方),发送方的发送窗口取接收窗口rwnd和拥塞窗口cwnd的最小值。
举例:
开始时,B通知A“老弟,我的接收窗口是400”。
流量控制-滑动窗口
注:填充黄色的为发送方A的发送窗口,绿色字体代表已发送的数据(接收方不一定接收,看ack)。
最后,B通知A接收窗口为0,这时,B可能在忙着给应用层传输数据。那么,什么时候A可以再给B发送数据呢?需要B再次给A发送一个报文段,通知A“老弟,你可以发送数据了,rwnd=xxx”。
但是,假如B发送的这个报文,A没有收到,这时A等待B通知,B等待A发送数据,就会死锁。为了解决这个问题,需要使用坚持计时器。
在发送方收到接收方的rwnd=0时,坚持计时器启动。坚持计时器到期,发送方发送零窗口探测报文段(仅1字节),询问接收方“老哥,你还不接收数据吗?”,如果B给A发送过了通知,这时接收到发送方的探测报文段,就知道它的通知丢失了,A没有收到,就会再发送通知,A接收到后继续发送数据,双方正常通信。
注:TCP规定,即使设置为零窗口,也必须接收以下几种报文段:零窗口探测报文段、确认报文段和携带紧急数据的报文段。
例题
[例题]主机甲和主机乙之间已建立了一个TCP连接,TCP最大段长度为1000字节。若主机甲的当前拥塞窗口为4000字节,在主机甲向主机乙连续发送两个最大段后,成功收到主机乙发送的第一个段的确认段,确认段中通告的接收窗口大小为2000字节,则此时主机甲还可以向主机乙发送的最大字节数是
A.1000 B.2000 C.3000 D.4000
[解析]发送窗口 = Min{rwnd,cwnd} = Min{2000,4000}=2000。第一个1000字节已确认,窗口滑动,第一个1000字节不在发送窗口中。由于第二个1000字节没有被主机乙确认,可能丢失,存在需要重传的可能性,这1000字节还在发送窗口中,因此,还可以发送的最大字节数是2000-1000=1000字节。之后主机甲等待主机乙确认或超时重传。
拥塞控制
出现条件:资源需求总和>可用资源。
目的:防止过多的数据注入到网络中。
假设:数据单方向传送,另一方向只传送确认,发送方接到确认后增加拥塞窗口大小。接收方有足够大的缓存空间,发送窗口取决于拥塞程度,即发送窗口=拥塞窗口。
为了讨论方便,纵坐标的单位为最大报文段,长度为MSS。横纵标单位为发送了一批报文段并收到他们确认的时间,即往返时延RTT。
给大家的福利
零基础入门
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
同时每个成长路线对应的板块都有配套的视频提供:
因篇幅有限,仅展示部分资料
网络安全面试题
绿盟护网行动
还有大家最喜欢的黑客技术
网络安全源码合集+工具包
所有资料共282G,朋友们如果有需要全套《网络安全入门+黑客进阶学习资源包》,可以扫描下方二维码领取(如遇扫码问题,可以在评论区留言领取哦)~
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!