TCP的核心性质
核心性质三:连接管理
有连接
连接:虚拟的,抽象的连接
通信双方各自保存对方的关键信息(IP,端口...)
连接如何建立的三次握手
连接如何断开的四次挥手
连接如何建立的 三次握手
handshake计算机术语
客套,打招呼,没有传达实质性的信息,通过打招呼唤起对方的注意
TCP中的握手,传输一个“打招呼”的数据包,这个数据包不携带任何“业务数据”(没有应用层的载荷)
TCP这个数据包只有报头,没有正文
也就是这个操作是不携带任何业务数据
三次握手,建立连接过程中,客户端和服务器要经过三次这样的“打招呼”,连接才能在双方这边都建立好
1)客户端给服务器发起一个syn(同步报文段)
客户端告诉服务器:我要和你建立连接,请你保存我的信息
2)服务器给客户端返回一个ack服务器告诉客户端:收到,我会保存
3)服务器也给客户端发起一个syn服务器也要告诉客户端:我也要和你建立连接请你保存我的信息
4)客户端收到之后,也返回一个ack客户端告诉服务器:收到,我会保存
在计算机中,通常一个术语,可能有多种用途需要结合上下文来理解含义
synchronized在多线程中表达的是"互斥"只能有一个,在咱们这个TCP这个地方,表达的是"通知"这样的效果
上述过程有四步,但是叫做“三次握手”的原因:
从流程/逻辑上是四次交互,但是中间两次,可以合并成一个TCP数据包
网络上实际只传输了三个数据包
服务器返回ack和发送syn都是内核控制的
和应用程序代码无关(程序员干预不了)
操作系统就可以在同一时间完成这俩数据的传输
三次握手的意义是什么,是用来解决什么问题的?
三次握手,也可以视为是一种“保证可靠传输的手段”(辅助手段)
- 三次握手,相当于“投石问路”,验证通信链路是否畅通
- 三次握手,也是在验证通信双方发送能力和接收能力是否正常
- 通过三次握手,让通信双方协商关键信息(和可靠性不是很相关,也有用) TCP建立连接过程中,有一个信息是需要协商的,就是TCP数据的起始序号。TCP的序号,针对载荷部分按照字节编号。当TCP连接建立好了之后,传输的第一个数据包的第一个字节的编号,不是从1/0开始编排... 而是在三次握手阶段协商出这样的数字,作为起始编号。
三次握手是和可靠传输有关系的
只不过是“前提条件”“辅助操作”真正传输数据的时候,靠的是确认应答和超时重传
编号不从0开始有什么用?
每次建立连接,协商出来的起始编号都是不同的(差别很大)
这样设定的目的,为了避免出现网络传输中的特殊情况
三次握手的意义:
1. 验证通信链路是否畅通
2. 验证通信双方的发送能力和接受能力
3. 协商关键信息
TCP建立连接过程中涉及到的 操作系统的 原生 API (Linux系统提供的C语言风格的api)
在Java里面对上面的api进行了大幅度的简化
我们只需要知道,客户端new Socket对象触发 三次握手
服务器这边通过accept把已经建立好的连接拿到应用程序中(accept接触阻塞的时候,三次握手已经完了)
LISTEN 服务器存在的状态
服务器new ServerSocket就会进入到LISTEN表示在“监听”这个端口,端口上过来客 户端,就能 accept了
ESTABLISHED 客户端和服务器连接建立好了.
客户端和服务器之间就可以进行通信了.
TCP断开连接(四次挥手)
断开连接的四次挥手,可能是客户端主动发起,也可能是服务器主动发起……
而三次握手,一定是客户端先发起。(倒果为因)
先发起的一方,定义为客户端
- 客户端告诉服务器,我要和你断开连接请你把我删了
- 服务器回应收到
- 服务器告诉客户端,我也要和你断开连接请你把我也删了
- 客户端回应收到
- 客户端和服务器都会把对方的信息(之前保存的对方的IP和端口)删除掉删除完了,连接就断开了
之所以叫做四次挥手,是因为中间两次交互,是不一定触发合并的(有的时候会合并,有的时候不会)
经典面试题:
建立连接的时候,必须握手三次吗?两次?四次?
四次:可以,但是没必要。
中间两次传输,时机是相同的。
合并成一次,有利于提高效率(封装分用2次 -> 1次)
两次:不可以,2次握手,无法完成“通信双方发送能力,接受能力的验证”
断开连接的时候,必须挥手四次吗?三次?——都可以
四次挥手的意义,就是为了“释放空间” ,建立连接需要保存信息,连接不用了,保存的信息自然就需要释放。
CLOSE_WAIT:
被动断开连接的一方进入的状态。
收到对方发来的FIN的时候,就会返回ACK,同时进入CLOSE_WAIT状态(理解成wait close,等待关闭,等待应用程序代码,调用close)
正常情况下,存在的时间会比较短。
如果你的服务器,出现了大量的CLOSE_WAIT很可能就是Bug
排查你的代码中是否调用了close
TIME_WAIT
(类似于线程TIMED_WAITING,有时间限制的等待)
等待连接彻底释放
进入时机:主动发起断开连接的一方,进入
我方发送FIN,对方返回ACK
对方发送FIN,我方返回ACK。同时进入TIME_WAIT
按理说,我方返回ACK,相当于四次挥手结束了
就可以释放连接了,实际上不能立即释放连接,而是要等等
等等,是为了应对最后一个ACK丢包的情况
TIME_WAIT等待时间,称为2 * MSL
MSL:网络上任意两点之间,传输消耗的最大时间
实际上,MSL给出的是一个 非常宽裕的值 比如Linux上默认是60s
TCP协议中的几个关键状态
LISTEN: 手机开机,信号良好,随时可以打电话
ESTABLISHED: 连接已经建立,电话接通,可以说话了
CLOSE_WAIT: 等待代码调用close
TIME_WAIT: 等待FIN重传,应对最后一个ACK丢包的情况