TCP/IP协议经常在面试中会被问到,基础的会问三次握手和四次挥手,更深一点可能会问TCP如何优化等问题,下面我们来再详细了解一下这些问题。
1. 前言
TCP/IP(Transmission Control Protocol / Internet Protocol)
TCP传输控制协议指一种面向连接的、可靠的、基于字节流的传输层通信协议。
下面我们会先回顾一下其报文格式,三次握手,四次挥手的一些基础知识。
TCP报文格式:
各部分的含义如下:
- 源端口,16bits 0~65525
- 目标端口 16bits
- sequence number : 数据序号,32 bits,TCP链接中传送的数据流中的每一个字节都编一个序号,序号字段的值指本报文段所发送的数据的第一个字节的序号。
- acknowledgement number: 确认序号:32 bits , 期望收到对方的下一个报文段的数据的第一个字节的序号
- URG : 紧急bit, URG=1时表示紧急指针字段有效,报文中有紧急字段,应该尽快传送。
- ACK :确认bit,当ACK=1时,确认字段号生效
- PSH :推送比特,接收方TCP收到PSH=1的报文段,就尽快地交付给接收应用进程,而不是在等到整个缓存都填满了再上传
- RST : 复位bit ,当RST=1时,表示TCP连接中出现严重错误,必须释放连接,然后重新建立传输连接。
- SYN :同步bit, 当SYN=1时,表明这是一个连接请求或者连接接受报文
- FIN :终止bit, 当FIN=1时,表明此报文的发送端的数据已经发送完毕,并要求释放连接。
- 接收窗口:16bit 用来控制对方发送的数据量,TCP连接的一端根据设置的缓存空间大小确定自己的接收窗口大小,然后通知对方确定对方的发送窗口的上线。
- 检验和:16bit 检验和字段检查的范围包括首部和数据这两部分。在对方计算检验和时,要在TCP报文段的前面加上12字节的伪首部。
- 紧急指针字段 16bit, 紧急指针指出在本报文段中的紧急数据的最后一个字节的序号
TCP三次握手:
三次握手的流程基本如下:
- 客户端发送连接请求,报文中SYN=1 , seq=10000
- 服务端收到请求之后会告诉客户端收到请求,ACK=1 , 确认序列号在请求序列号上加1, ack=10001,并向客户端请求SYN=1, seq=20000。
- 客户端收到请求之后告诉服务端收到请求,ACK=1,确认序列号在请求序列号上加1 seq=20001,至此TCP连接建立。
下图示意了一个完整的TCP三次握手
TCP四次挥手:
四次挥手握手的流程基本如下:
- 客户端传输完成,发送断开连接请求,其中FIN=1,seq=25000。
- 服务端收到断开请求之后,会立即发送响应,ACK=1, ack=25001,表示收到断开连接的请求。
- 服务端相关连接处理好之后,同样会向客户端发送断开请求,FIN=1, seq =30000,
- 客户端等待一段时间之后收到服务端断开连接的请求,会发送响应数据,ACK=1,seq=30001.至此TCP连接断开。
下图为完整的TCP四次挥手完整示意
2.TCP在面试中如何回答
请讲一下对TCP的理解
回答如下:
TCP/IP协议是传输层面相连接的安全可靠的一个传输协议,三次握手机制是为了保证能建立一个安全可靠的连接。
第一次握手是由客户端发起的,客户端会向服务端发送一个报文,在报文里面,SYN=1.表示发起一个新连接。服务端收到此报文之后,就明白客户端需要建立连接,此时会发送确认消息包 标志位 ACK=1。此时为了保证服务端确认客户端能收到消息,就需要客户端在发送收到消息的响应报文,ACK=1。通过上述的3次握手,客户端和服务端均可以确认能收到互相之间的消息,此时安全连接建立。
四次挥手也是为了保证完全释放TCP连接,四次挥手有传输完数据的一方先发起。假设客户端数据传输完成,则发起断开连接请求FIN=1 给到服务端 并状态设置成FIN_WAIT_1, 服务端收到断开连接请求后,会立马发送一个响应请求, 服务端状态变成CLOSE_WAIT。然后客户端收到服务端的响应之后进入FIN_WAIT_2状态。
服务端数据传输完成之后会发动断开连接请求,并将状态设置成LAST_ACK,客户端收到请求之后发送最终确认关闭请求给服务端,进入TIMW_WAIT状态,一段时间之后客户端连接close。服务端收到最终响应之后也会由LAST_ACK状态变成CLOSE状态,
为何挥手需要4次
TCP有半关闭的特性,其连接的一端结束它的发送后还能接收来自另一端数据的能力。双方都可以在数据传输完成之后发起断开连接的请求,对方确认进入半关闭状态之后,另一边也没有数据发送时则发送断开连接通知,对方确认后就完全关闭TCP连接。尽量让双方安全完成数据传输。
挥手报文丢失的几种情况
第一次挥手丢失报文
假设客户端发起断开连接请求后,客户端一直没有收到服务端的ACK响应报文,那么客户端会触发超时重传机制,超过一定的重传次数之后,直接进入close状态
第二挥手丢失报文
服务端收到断开连接请求,并发送了响应报文,但是客户端一直都没有收到报文。这种情况和第一种情况相似,客户端会触发超时重传
第三次挥手丢失报文
服务端数据传输完成后,发送FIN断开连接通知之后,服务端进入LAST_ACK状态,但是客户端没有收到请求,一直没有响应。此时服务端会触发超时重传机制。
第四次挥手丢失报文
客户端收到服务端的FIN报文之后,会发送响应报文,并进入TIMW_WAIT状态,一段时间后客户端TCP连接关闭。但是服务端没有收到响应报文,服务端会触发超时重传机制,最后close。
3. TCP的优化
全队列溢出优化
当大量TCP请求进入到服务端时,服务端会将已经返回响应的请求的连接存放到半连接队列(SYN queue),当服务端收到客户端发来的ACK包之后,连接建立,此时会将连接从SYN-queue中取出来放到全连接队列(accept queue),等待进程调用accept函数时将连接取出来。
这两个队列都有长度限制,超过长度限制之后,内核会直接丢弃链接或者返回RST包。Linux默认是丢弃连接, 也可以设置向客户端发送RST复位报文,通知客户端连接失败。(修改tcp_abort_on_overflow的值为1).
通常情况下tcp_abort_on_overflow应该保持默认值,这样有利于应对突发流量。
同时我们可以适当增大全连接队列的长度限制(Tocmate中可以设置acceptCount,Nginx可以调整tcp_max_syn_backlog的值)
TCP Fast Open
当TCP连接使用完之后,客户端再次向服务器请求建立连接,报文中可以记录此前的Fast Open Cookie。服务器对Cookie进行校验之后,如果Cookie有效,就可以将数据给到程序处理,相当于绕过了三次握手,可以更快的建立连接。
linux可以设置tcp_fastopen 来打开Fast Open功能。(PS: Fast Open需要客户端和服务端同时支持才有效)
连接复用
在客户端发起建立建立线连接时,可以复用处于TIME_WAIT状态的连接,linux中可以设置tcp_tw_reuse参数。
传输过程中调节缓冲区大小
系统会为每个连接建立缓冲区, 接收缓冲区可以根据系统空闲内存的大小来调节接收窗口。
发送缓冲区的调节功能是自动开启的,接收缓冲区设置tcp_moderate_rcvbuf=1表示开启调节功能。
高并发服务中,可以调整缓冲区的动态调整可以达到最大宽带延积。如果服务是网络IO型的话,可以调大tcp_mem的上限,让TCP连接可以使用更多的系统内存,有利于提高并发。
总结
针对TCP的优化,有如下的的一些建议:
- 服务端配置
- 可以使用新版本的服务器
- 适当增大TCP的全连接队列最大限制。
- TCP快速打开
- 应用程序
- 减少数据发送,压缩要发送的数据
- 减少数据发送距离,部署CDN等
- 尽量重用TCP连接
-
通信协议
+关注
关注
28文章
879浏览量
40294 -
数据
+关注
关注
8文章
7002浏览量
88937 -
TCP协议
+关注
关注
1文章
91浏览量
12070 -
服务端
+关注
关注
0文章
66浏览量
7004
发布评论请先 登录
相关推荐
评论