1. 计算机网络体系结构
七层模型

七层模型是一个标准化分层模型,共分七层,物理层(网卡)、数据链路层(驱动)、网络层(ip)、传输层(tcp)、会话层、表示层、应用层。 相对简单的类比理解就是分别对应计算机的网卡、驱动、ip地址、tcp协议传输层。
五层模型

五层模型就是将应用层,表示层和会话层一起统称为应用层。各层的对照关系如下:
- IP地址属于网络层
- tcp、udp协议属于传输层
- http、ftp、DNS等属于应用层
2.TCP/IP网络传输
数据的流转是在每层中逐步包装,最后通过网络发送给对端,同时对端拿到网络中的数据包后进行层层拆分,获取数据。由下图进行简单的介绍:

- 用户A在应用程序中,希望将字符串传递给对端的用户B; 应用层将字符串传递给传输层,也就是tcp层
- tcp层负责建立链接、发送数据,关闭链接。为了将应用层的数据发送到对端,会将应用数据封装成报文段并加上一个TCP的首部,再向下传递。
- 同理 IP层会将上层的数据进行封装并加上一个IP的首部,再向下传递。
到达对端后
- 先解析获取MAC值,确定该数据包是否是发给自己的,如果不是就丢弃,是的话就开始进行逐层的解析。
- 最终在应用层拿到了用户A发送的数据。
TCP协议
TCP(Transmission Control Protocol)是面向连接的通信协议,通过三次握手建立连接,然后才能开始数据的读写,通讯完成时要拆除连接,由于TCP是面向连接的所以只能用于端到端的通讯。
TCP提供的是一种可靠 的数据流服务,数据有可能被拆分后发送,那么采用超时重传机制 和应答确认机制是组成TCP可靠传输的关键设计。
而超时重传机制中最最重要的就是重传超时(RTO,Retransmission TimeOut)的时间选择,实际的网络环境是十分复杂多变的,有些环境会经常的出现网络抖动,有些环境又是非常顺畅的。所以这个时候超时应该是因地制宜,因时制宜的,而不是使用一个固定的数值。
超时的时长就需要根据网络情况动态调整,就需要采样统计一个数据包从发送端发送出去到接收到这个包的回复这段时长来动态设置重传超时值 ,这个时长就是为RTT,学名round-trip time,然后再根据这个RTT通过各种算法和公式平滑RTT值后,最终确定重传超时值。 而IP层进行数据传输时,是不能保证数据包按照发送的顺序达到目的机器。当IP将把它们向'上'传送到TCP层后,TCP将包排序并进行错误检查。TCP数据包中包括序号和确认,所以未按照顺序收到的包可以被排序,而损坏的包可以被重传。
TCP还采用一种称为"滑动窗口"的方式进行流量控制,所谓窗口实际表示接收能力,用以限制发送方的发送速度。
同时TCP还允许在一个TCP连接上,通信的双方可以同时传输数据,也就是所谓的全双工。
TCP三次握手
三次握手是指建立一个 TCP 连接时需要客户端和服务器端总共发送三个包以确认连接的建立。每次tcp链接的建立都是始于客户端主动发起链接请求,服务端进行应答。

简单版本的理解三次握手,可以带入一个场景:
标准的解读:
- 客户端发起一个链接请求,将请求报文的SYN标志为设置为1,请求报文的Sequence Number字段(简称seq)中填入一个随机值J,并将该数据包发送给服务器端,客户端进入SYN_SENT状态,等待服务器端确认。
- 服务端收到报文后,识别SYN为1判断出是链接请求;服务器返回应答报文SYN=1,ACK=1,ack=J+1,应答报文中的seq填入一个随机值K,将该数据包发送给客户端以确认链接响应。服务端进入SYN_RCVD状态。(ack的机制方便双方了解包的序号以及若需要重传的内容)
- 客户端收到应答报文后,检查ack是否为J+1,ACK是否为1,如果正确则将第三个报文标志位ACK置为1,ack=K+1,并将该数据包发送给服务器端,服务器端检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,客户端和服务器端进入ESTABLISHED状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。
为什么是进行三次握手
因为已知TCP是可靠的数据传输,所以通信双方需要维护了解发出去的数据包哪些已被接受,哪些还需要进行重传等等。这个时候就需要维护一个序列号,也就是上面所说的seq和ack。
例如:发送方在发送数据包(假设大小为 10 byte)时,同时送上一个序号(假设seq为500),那么接收方收到这个数据包以后,就可以回复一个确认号(510 = 500 + 10)告诉发送方"我已经收到了你的数据包,数据包大小是10Byte,你可以发送下一个数据包了,序号从 511 开始"。
再回到为什么是三次握手上面来,因为三次握手是保证通信双方都能确认对方已接受到链接请求的最小通信数。两次的话无法保证双方都确认接受到链接请求。有可能服务器发送的接受链接请求的报文在网络传输中丢失,这样无法保证双方都确认。
洪泛攻击
三次握手中有一个第二次握手,服务端向客户端应答请求,应答请求是需要客户端IP的,而且因为握手过程没有完成,操作系统使用队列维持这个状态(Linux 2.2以后,这个队列大小参数可以通过/proc/sys/net/ipv4/tcp_max_syn_backlog设置)。
于是攻击者就伪造这个IP,往服务器端狂发送第一次握手的内容,当然第一次握手中的客户端IP地址是伪造的,从而服务端忙于进行第二次握手,但是第二次握手是不会有应答的,所以导致服务器队列满,而拒绝连接。
解决洪泛攻击常见的方案就是设置防火墙。
四次挥手
同样可以情景化的理解一下:
标准理解

- 通信双方的一方首先调用close,我们称该端执行主动关闭(active close)。该端的TCP于是发送一个FIN分节,表示数据发送完毕,应用进程进入FIN-WAIT-1(终止等待1)状态。
- 接收到这个FIN的对端执行被动关闭(passive close),发出确认报文。因为FIN的接收意味着接收端应用进程在相应连接上再无额外数据可接收 ,接收端进入了CLOSE-WAIT(关闭等待)状态,这时候处于半关闭状态,即主动关闭端已经没有数据要发送了,但是被动关闭端若发送数据,主动关闭端依然要接受 。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。主动关闭端收到确认报文后进入FIN-WAIT-2(终止等待2)状态。
- 被动关闭的应用进程将所有的数据都发送完后,将调用close关闭它的套接字。这导致它的TCP也发送一个FIN,表示它也没数据需要发送了,可以彻底的关闭链接了。
- 接收这个最终FIN的原发送端TCP(即执行主动关闭的那一端)确认这个FIN发出一个确认ACK报文,并进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗MSL(的时间后,当主动关闭端撤销相应的TCB后,才进入CLOSED状态。
- 被动关闭端只要收到了客户端发出的确认,立即进入CLOSED状态。
TIME-WAIT状态
通常是2*MSL的时间长度。
MSL : 最长报文段寿命/最长分节生命期 max segement lifetime,MSL是任何IP数据报能够在因特网中存活的最长时间,任何TCP实现都必须为MSL选择一个值。建议值是2分钟,不过源自Berkelcy的实现传统上改用30秒这个值。这意味着TIME_WAIT状态的持续时间在1分钟到4分钟之间。
回到为什么需要这个TIME-WAIT状态呢?
- 还是因为TCP是可靠的链接; 比如主动关闭端的最后一个ACK报文在网络传输过程中丢失了,对端在规定的时间没有获取到后会进行重传,这个时候需要客户端来处理请求。
- 让迟到的报文被正确处理; 比如服务端最后发送的数据报文在网络中进行延迟,在客户端发出最后的ACK包后到达客户端,此时这段数据报文依然需要被处理。
为什么需要四次挥手
这个就很好理解了,需要双发都把该发的数据都发送完。所以需要进行四次挥手。