一、传输层
1.1 传输层给应用层提供了什么样的服务?
传输层为应用层的进程提供数据传输服务,主要分为无连接与面向连接的传输服务。
2.1 UDP
UDP是无连接、尽力而为的传输层协议,提供了多路复用和简单的差错检测功能。
UDP的首部长度为8个字节,分别为源端口、目的端口、UDP报文长度、UDP校验和,各占2字节。
UDP报文的首部开销小、没有建立连接带来的开销。UDP广泛应用于客户-服务器RPC和实时多媒体领域。
3.1 TCP
TCP是面向连接、可靠的、提供拥塞控制、流量控制的传输层协议。
TCP的连接是全双工的、点到点的,因此TCP不支持组播、广播的传输模式。
TCP的连接就是一个字节流,而不是消息流,端和端之间不保留消息的边界。
3.2 TCP的三次握手过程,为什么需要三次握手,为什么不是两次或者是四次?
- 服务器调用LISTEN、ACCEPT原语,然后被动的等待连接请求。
- 客户端调用CONNECT原语,同时指定其IP和端口号等参数后,CONNECT原语发送一个SYN报文。
- 服务器的TCP实体检查是否有进程在目标端口LISTEN,如果没有返回一个RST报文,拒绝客户端的请求,如果有就交个在该端口监听的进程,进程可以接受或拒绝连接,如果接受就会发送给客户端一个SYNACK报文,同时为该TCP连接分配缓存和资源,因此TCP容易受到SYN flood的攻击。
- 客户端接受到SYNACK报文后,会给该TCP连接分配缓存和资源,然后向服务器发送带ACK的数据包,该报文可以携带客户端到服务端的数据。
TCP的核心目标是在实现可靠传输的前提下,尽可能的提高传输效率。为了实现可靠传输,TCP通信双方都必须维护一个序号,用来标记发送的数据包是否被对端成功收到。三次握手的过程就是通信双方互相告知自己初始序号,并确认对方收到了自己的初始序号。如果是两次握手,则只有发送方的初始序号才会得到确认。而四次握手的第2次和第3次握手可以被合并为1次,从而提高传输效率。
如果是两次握手,还会出现如下问题,出现过期的SYN报文与目标主机建立连接。
客户端A向服务器B发送SYN报文,因为某种因素,该报文决定浏览网络世界中的各个奇怪的角落,于是客户端A发生超时,重新发送SYN报文,与服务器建立连接、发送数据、断开连接后,第一次的SYN报文才迟迟到达了服务器,服务器B以为是一个新的连接请求,于是发送SYNACK,重新建立了一个TCP连接。
3.3 为什么TCP建立连接使用随机的初始序列号?
之所以采用随机的初始序号,主要的目的是避免会话被劫持,TCP协议采用两个条件来确认已经建立连接的TCP通道,第一个是基础连接确认(源IP,源端口,目的IP,目的端口),第二个是序号标识(SEQ),如果知道了这两个条件,就可以进行会话劫持,因此出于网络安全的考虑,序列号一定是越随机越好。第二点是防止序号回绕,在一个传输间隔内,序号不能重复出现。 如果采用相同的序列号,服务端可能接收到旧的连接传送的无效的过时的报文数据
3.4 服务器如何避免SYN洪泛攻击?
SYN洪泛攻击是向服务器发送大量的SYN连接报文,但是却不进行最后的响应,以此来耗光服务器的志愿。
常用的方式有:
- 增加tcp_max_syn_backlog的值
- 减少tcp_synack_retries的值
- 回收最早的半开连接
- 采用tcp_syncookies
当启用tcp_syncookies时,backlog满了后,linux内核生成一个特定的n值(n为随机初始序号),而并不给客户端的连接分配资源。当客户端提交第三次握手的ACK包时,linux内核取出n值,进行校验,如果通过,则认为这个是一个合法的连接。
3.5 TCP的4次挥手,为什么需要4次,为什么要等待2MSL
过程:
- 客户端向服务器发送FIN报文,进入FIN_WAIT1阶段
- 服务器收到FIN报文后,向客户端发送ACK报文,进入CLOSE_WAIT,客户端收到ACK后悔进入FIN_WAIT2阶段
- 服务器主动向客户端发送FIN报文,进入LAST_ACK阶段
- 客户端收到FIN报文后,进入TIME_WAIT阶段,2个MSL后关闭连接,并向服务器发送ACK报文,服务器收到后连接关闭
断开连接的过程的第2步和第3步不能合并,因为接收到FIN报文后,服务器可能还有数据没有发送完毕,所以不能立刻发送FIN报文。
如果不等待2MSL,如果客户端发送的ACK丢失,服务器会一直等待ACK,导致连接无法释放;等待2MSL同时也保证了服务器在CLOSE_WAIT阶段发送的数据不会滞留在网络中。
3.6 TCP往返时间估计和超时
- 为非重传的报文计算往返时间,记为SampleRTT,并根据SampleRTT计算EstimatedRTT EstimatedRTT = (1 - a) * EstimatedRTT + a * SampleRTT, a的默认值为0.125
- 计算往返时间的波动,记为DevRTT DevRTT = (1 - b) * DevRTT + b * Math.abs(SampleRTT - EstimatedRTT), b的默认值为0.25
- 设置超时时间 TimeoutInterval = EstimatedRTT + 4 * DevRTT
3.7 TCP拥塞控制
出现拥塞的标志就是,报文超时或者3个冗余的ack。 TCP常用的拥塞控制算法是Reno算法,过程如下:
- 当拥塞窗口小于窗口阈值时,采用慢开始的方式,收到确认后,将拥塞窗口翻倍
- 当拥塞窗口大于窗口阈值时,采用拥塞避免的方式,收到确认后,将拥塞窗口加1
- 当接收到3个冗余ack时,会采用快重传,立刻重传请求的报文段,然后采用快恢复算法,将窗口阈值减半,设置拥塞窗口大小与窗口阈值的大小相同,继续采用拥塞避免。