传输层

传输层主要功能为两台主机上的应用程序提供端到端的通信,通过端口号识别两台主机上相对应程序之间进行通信。

网络层为主机之间提供逻辑通信,而传输层为应用程序之间提供端到端的逻辑通信。

传输层最重要的两种协议:面向连接的TCP(传输控制协议,Transmission Control Protocol)和无连接的UDP(用户数据报协议,User Datagram Protocol)。所传输的数据单元分别称为TCP报文段(segment)和UDP用户数据报。

UDP

用户数据报协议只在IP的数据报服务上增加了很少的功能,就是复用和分用以及差错检测的功能。
UDP的主要特点:

  1. UDP是无连接的,即发送数据之前不需要建立连接,因此减少了开销和发送数据之前的时延。
  2. UDP使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的连接状态表。
  3. UDP是面向报文的。UDP对应用层交下来的报文,既不合并也不拆分,在添加首部后就交给网络层。如果UDP数据报太长,网络层会在传送时进行分片
  4. UDP没有拥塞控制,因此网络出现的拥塞不会使源主机的发送速率下降。
  5. UDP支持一对一、一对多、多对一和多对多的交互通信
  6. UDP的首部开销小,只有8个字节,TCP有20个字节。

TCP

传输控制协议TCP的主要特点:

  1. TCP是面向连接的。应用程序使用TCP协议之前需要建立TCP连接,数据传输完毕后需要释放已建立的TCP连接。
  2. 每条TCP连接只能有两个端点,广播和多播不能用于 TCP。
  3. TCP提供可靠交付的服务。也就是,通过TCP连接传送的数据,无差错、不丢失、不重复、并且按序到达。
  4. TCP提供全双工通信。TCP允许通信双方的应用进程在任何时候都能发送数据。
  5. 面向字节流。采用TCP协议进行数据传输是不会造成网络层分片的,因为TCP会对报文进行分段处理,接收方的TCP协议会对其进行还原。
  6. 使用滑动窗口机制来实现流量控制,通过改变窗口大小进行拥塞控制。
  7. TCP使用校验和,确认和重传机制来保证可靠传输。

TCP连接

TCP连接的端点叫做套接字(Socket)或插口,端口号拼接到IP地址即构成了套接字。

每一条TCP连接被通信的两端的两个断点所确定。

TCP连接是由协议所提供的一种抽象。

TCP运输连接管理

TCP是面向连接的协议,运输连接分为3个过程:连接建立数据传送连接释放
常见网络状态及其描述

状态 描述
CLOSED 表示初始状态,TCP进程都处于关闭状态
LISTEN 表示服务器端的某个SOCKET处于监听状态,可以接受连接
SYN_SENT 表示客户端已发送了SYN报文
SYN_RCVD 表示服务端接收到了SYN报文
ESTABLISHED 表示TCP连接成功建立
FIN_WAIT_1 表示主动关闭连接,主动发送FIN报文
FIN_WAIT_2 表示被动关闭方同意关闭连接,主动关闭连接方收到被动关闭方返回的ACK后,进入该状态
TIME_WAIT 表示收到对方的FIN报文并发送了ACK报文,就等 2MSL 后即可回到 CLOSED 状态了。如果 FIN_WAIT_1 状态下,收到对方同时带FIN标志和ACK标志的报文时,可以直接进入 TIME_WAIT 状态,而无须经过 FIN_WAIT_2 状态。
CLOSING 表示双方都在关闭连接,双方同时发送FIN报文
CLOSE_WAIT 表示被动关闭方等待关闭,
LAST_ACK 表示被动关闭方发送FIN报文后,最后等待对方的ACK报文。当收到ACK后进入CLOSED状态。

TCP三次握手(连接建立)

采用三次握手来建立一次连接。

  1. 第一次握手
    建立连接时,客户端发送SYN包给服务器,并进入SYN_SEND状态,等待服务器的确认。
  2. 第二次握手
    服务器收到SYN包后,必须确认客户端,所以发送ACK包,同时服务器还必须发送SYN包等待客户端的确认,此时服务器进入到SYN_RCVD状态。
  3. 第三次握手
    客户端收到SYN+ACK包之后,向服务器发送确认包ACK,该包发送完毕,此时客户端与服务器进入ESTABLISHED状态,两者可以进行数据交换,完成三次握手。

TCP四次挥手(连接释放)

由于TCP连接是全双工的,因此每个方向上都必须单独进行关闭,当一方完成数据发送任务后就能发送一个FIN来表示终止这个方向的连接,收到一个FIN意味着这个方向不再有数据传送但另一方向仍能继续发送数据,直到另一方向也发送FIN报文

  1. 第一次挥手
    客户端主动向服务端发出连接释放请求FIN,并停止发送数据,进入FIN_WAIT_1状态,等待服务端确认。
  2. 第二次挥手
    服务端收到连接释放请求报文后,发出确认释放连接的报文ACK,然后服务端进入CLOSE_WAIT关闭等待状态。
    此时TCP连接处于半关闭状态,客户端已经不向服务端发送数据,但是服务端仍可以向客户端发送数据。
  3. 第三次挥手
    客户端收到服务器的确认信息后,就进入了FIN_WAIT_2状态,等待服务端发出连接释放请求报文。如果服务端没有数据需要传输,服务端会发出释放连接的请求FIN,服务端进入到LAST_ACK状态。
  4. 第四次挥手
    客户端收到服务端的连接释放请求后,必须对此发出确认,客户端进入到TIME_WAIT状态。在这段时间内TCP连接并没有释放,必须等待2MSL(最长报文段寿命)时间后,客户端才进入到CLOSED状态。服务端收到客户端的确认应答后,就进入了CLOSED状态。
    直到客户端和服务端都进入CLOSED状态后,连接就完全释放了。

SYN Flood(SYN攻击)

在三次握手过程中,服务器发送 SYN-ACK 之后,收到客户端的 ACK 之前的 TCP 连接称为半连接(half-open connect)。此时服务器处于 SYN_RCVD 状态。当收到 ACK 后,服务器才能转入 ESTABLISHED 状态。

SYN 攻击指的是,攻击客户端在短时间内伪造大量不存在的IP地址,向服务器不断地发送SYN包,服务器回复确认包,并等待客户的确认。由于源地址是不存在的,服务器需要不断的重发直至超时,这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,导致目标系统运行缓慢,严重者会引起网络堵塞甚至系统瘫痪。
SYN 攻击是一种典型的 DoS/DDoS 攻击。

SYN攻击不能完全被阻止,除非将TCP协议重新设计。我们所做的是尽可能的减轻SYN攻击的危害,常见的防御 SYN 攻击的方法有如下几种:

  • 缩短超时(SYN Timeout)时间
  • 增加最大半连接数
  • 过滤网关防护
  • SYN cookies技术

问题

  1. 为什么在 TCP 协议里,建立连接是三次握手,而关闭连接却是四次挥手?
    因为当处于 LISTEN 状态的服务器端收到来自客户端的 SYN 报文(客户端希望新建一个TCP连接)时,它可以把 ACK (确认应答)和 SYN (同步序号)放在同一个报文里来发送给客户端
    但在关闭 TCP 连接时,当收到对方的 FIN 报文时,对方仅仅表示对方已经没有数据发送给你了,但是你自己可能还有数据需要发送给对方,则等你发送完剩余的数据给对方之后,再发送 FIN 报文给对方来表示你数据已经发送完毕,并请求关闭连接,所以通常情况下,这里的 ACK 报文和 FIN 报文都是分开发送的。
  2. 三次握手中,为什么需要客户端还发送一次确认?

    这主要是为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误连接。

    假设客户端发送连接请求在某些网络节点滞留了,客户端重新发起一次连接请求正确建立连接,但是如果这个滞留的连接请求(已失效的连接请求)在成功建立的连接释放后的某个时间才到达服务端,假设没有第三次握手,那么这次失效的连接请求又会建立一个新连接。

TCP重传机制

TCP要保证所有的数据包都可以到达,所以,必需要有重传机制。

注意,接收端给发送端的Ack确认只会确认最后一个连续的包,比如,发送端发了1,2,3,4,5一共五份数据,接收端收到了1,2,于是回ack 3,然后收到了4(注意此时3没收到),此时的TCP会怎么办?我们要知道,SeqNum和Ack是以字节数为单位,所以ack的时候,不能跳着确认,只能确认最大的连续收到的包,不然,发送端就以为之前的都收到了。

超时重传机制

每次发送数据包时,发送的数据报都有seq号,接收端收到数据后,会回复ack进行确认,表示某一seq号数据已经收到。发送方在发送了某个seq包后,等待一段时间,如果没有收到对应的ack回复,就会认为报文丢失,会重传这个数据包。

针对上面的情况,接收端不回ack,死等3,当发送方发现收不到3的ack超时后,会重传3。一旦接收方收到3后,会ack 回 4——意味着3和4都收到了。但是,这种方式会有比较严重的问题,那就是因为要死等3,所以会导致4和5即便已经收到了,而发送方也完全不知道发生了什么事,因为没有收到Ack,所以,发送方可能会悲观地认为也丢了,所以有可能也会导致4和5的重传。

快速重传机制

接收数据一方发现有数据包丢掉了。就会发送ack报文告诉发送端重传丢失的报文。如果发送端连续收到标号相同的ack包,则会触发客户端的快速重传。比较超时重传和快速重传,可以发现超时重传是发送端在傻等超时,然后触发重传;而快速重传则是接收端主动告诉发送端数据没收到,然后触发发送端重传。

比如:如果发送方发出了1,2,3,4,5份数据,第一份先到送了,于是就ack回2,结果2因为某些原因没收到,3到达了,于是还是ack回2,后面的4和5都到了,但是还是ack回2,因为2还是没有收到,于是发送端收到了三个ack=2的确认,知道了2还没有到,于是就马上重转2。然后,接收端收到了2,此时因为3,4,5都收到了,于是ack回6。

TCP滑动窗口和流量控制

滑动窗口

client 和 server 各自协议栈都有自己的 buffer,应用层读写数据的源都是协议栈 buffer 里。
以接收端为例,应用程序调用read()时,会从buffer里移走数据到用户空间,应用程序读的速度越快(read(1024)必然比read(1)要快),那么buffer里的内容消费的越快,buffer也会越空。那么TCP就可以告诉client,我现在很闲,你可以发送更多的数据来。”更多”是多少?这就说窗口,窗口就是量化接收端当前能处理数据的能力

client 和 server 端建立连接后,client会告诉server,自己的”接收窗口“大小(自己能接收多少的数据,受上面所说的buffer影响),server 端接收到 client 的”接收窗口”大小,就会变成server端自己的”发送窗口“大小。同样的,server端告诉client自己的”接收窗口”大小,就会变成客户端的”发送窗口”大小。

流量控制

  1. 接收端的窗口越来越小,那么就是接收端处理不过来(1.发的程序太快,太多;2.收的程序太慢,太少;3.发端带宽比收端带宽更大),会导致接收端发送给发送端的窗口变小,从而发送端调整发送窗口大小,降低发送速度,网络流量就会下降。
  2. 接收端的窗口越来越大,那么就是发送端处理不过来(1.收的程序太快,太多;2.发的程序太慢,太少;3.发端带宽比收端带宽更小),会导致接收端发送给发送端的窗口变大,从而发送端调整发送窗口大小,增加发送速度,网络流量就会升高。

感谢:
https://github.com/xuelangZF/CS_Offer/blob/master/Network/TCP.md