✍个人博客:https://blog.csdn.net/Newin2020?type=blog
📣专栏地址:http://t.csdnimg.cn/fYaBd
📚专栏简介:在这个专栏中,我将会分享 C++ 面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
85. 两端同时打开会怎样?
如果双方同时发 SYN 报文,状态变化会是怎样的呢?
这是一个可能会发生的情况。
状态变迁如下:
在发送方给接收方发 SYN 报文的同时,接收方也给发送方发 SYN 报文,两个人刚上了!
发完 SYN,两者的状态都变为 SYN-SENT。
在各自收到对方的 SYN 后,两者状态都变为 SYN-REVD。
接着会回复对应的 ACK + SYN,这个报文在对方接收之后,两者状态一起变为 ESTABLISHED。
这就是同时打开情况下的状态变迁。
86. 说说 TCP 快速打开的原理 (TFO)
优化的过程是这样的,还记得我们说 SYN Flood 攻击时提到的 SYN Cookie 吗?这个 Cookie 可不是浏览器的Cookie,用它同样可以实现 TFO。
TFO 流程
(1) 首轮三次握手
首先客户端发送 SYN 给服务端,服务端接收到。
注意哦!现在服务端不是立刻回复 SYN + ACK,而是通过计算得到一个SYN Cookie,将这个 Cookie 放到 TCP 报文的 Fast Open选项中,然后才给客户端返回。
客户端拿到这个 Cookie 的值缓存下来。后面正常完成三次握手。
首轮三次握手就是这样的流程。而后面的三次握手就不一样啦!
(2) 后面的三次握手
在后面的三次握手中,客户端会将之前缓存的 Cookie、SYN 和 HTTP 请求 (是的,你没看错) 发送给服务端,服务端验证了 Cookie 的合法性,如果不合法直接丢弃;如果是合法的,那么就正常返回 SYN + ACK。
重点来了,现在服务端能向客户端发 HTTP 响应了!这是最显著的改变,三次握手还没建立,仅仅验证了 Cookie 的合法性,就可以返回 HTTP 响应了。
当然,客户端的ACK还得正常传过来,不然怎么叫三次握手嘛。
流程如下:
注意:客户端最后握手的 ACK 不一定要等到服务端的 HTTP 响应到达才发送,两个过程没有任何关系。
TFO 的优势
TFO 的优势并不在与首轮三次握手,而在于后面的握手,在拿到客户端的 Cookie 并验证通过以后,可以直接返回 HTTP 响应,充分利用了 1 个RTT (Round-Trip Time,往返时延) 的时间提前进行数据传输,积累起来还是一个比较大的优势。
87. 没有 listen 能建立 TCP 连接吗?
服务端没有 listen,客户端发起连接建立,会发生什么?
服务端如果只 bind 了 IP 地址和端口,而没有调用 listen 的话,然后客户端对服务端发起了连接建立,服务端会回 RST 报文。
不使用 listen ,可以建立 TCP 连接吗?
答案,是可以的,客户端是可以自己连自己的形成连接(TCP 自连接),也可以两个客户端同时向对方发出请求建立连接(TCP 同时打开),这两个情况都有个共同点,就是没有服务端参与,也就是没有 listen,就能建立连接。
那没有 listen,为什么还能建立连接?
我们知道执行 listen 方法时,会创建半连接队列和全连接队列。
三次握手的过程中会在这两个队列中暂存连接信息。
所以形成连接,前提是你得有个地方存放着,方便握手的时候能根据 IP + 端口等信息找到对应的 socket。
那么客户端会有半连接队列吗?
显然没有,因为客户端没有执行 listen,因为半连接队列和全连接队列都是在执行
listen 方法时,内核自动创建的。
但内核还有个全局 hash 表,可以用于存放 sock 连接的信息。
这个全局 hash 表其实还细分为 ehash,bhash 和 listen_hash 等,但因为过于细节,大家理解成有一个全局 hash 就够了。
在 TCP 自连接的情况中,客户端在 connect 方法时,最后会将自己的连接信息放入到这个全局 hash 表中,然后将信息发出,消息在经过回环地址重新回到 TCP 传输层的时候,就会根据 IP + 端口信息,再一次从这个全局 hash 中取出信息。于是握手包一来一回,最后成功建立连接。
TCP 同时打开的情况也类似,只不过从一个客户端变成了两个客户端而已。