TCP的三次握手是用于建立连接
指建立一个TCP连接时 需要客户端和服务端总共发送3个包以确认连接的建立
在socket编程中 这一过程由客户端执行connect来触发
第一次握手:Client将SYN置为1 随机产生一个值seq=j 并将数据包发送给Server Client进入SYN_SENT状态 等待Server确认
第二次握手:Server收到包后由SYN=1知道Client请求建立连接 Server将SYN和ACK都置为1 ack=j+1 随机产生一个值seq=k 并将该数据包发送给Client以确认连接请求 Server进入SYN_RCVD状态
第三次握手:Client收到确认后 检查ack是否为+1 ack是否为1 如果正确则将ack置为1 ack=k+1 并将该数据包发送给Server Server检查正确则连接建立成功 Client和Server进入ESTABLISHED状态 完成三次握手 随后Client与Server之间开始传输数据
为什么需要三次握手 两次不可以吗 或者四次五次可以吗?
----分析一种特殊情况 假设客户请求建立连接 发给服务器SYN包等待服务器确认 服务器收到确认后 如果是两次握手 假设服务器给客户端在第二次握手时发送数据 数据从服务器发出 服务器认为连接已经建立 但在发送数据但过程中数据丢失 客户端认为连接没有建立 会进行重传 假设每次发送的数据一直在丢失 客户端一直SYN 服务器就会产生多个无效连接 占用资源 这个时候服务器可能会挂掉 这个现象就是 SYN的洪水攻击
---- 第三次握手是为了防止 如果客户端迟迟没有收到服务器确认报文 这时会放弃连接重新启动一条连接请求 但问题是 服务器不知道客户端没有收到 所以他会收到两个连接 浪费连接开销 如果每次都是这样 就会浪费多个连接开销
TCP的四次挥手 主要是说TCP端口断开连接的时候
第一次挥手:主机1(可以是客户端 也可以是服务器) 向主机2发送一个 FIN 报文段 此时主机1进入 FIN_WAIT_1状态 表示主机1没有数据要发送给主机2 了
**第二次挥手:**主机2收到了主机1发送的 FIN 报文段 向主机1回了一个 ACK报文段 主机1进入FIN_WAIT_2状态 主机2告诉主机1 我也没有数据要发送了 可以进行关闭连接了
第三次挥手: 主机2向主机1发送 FIN报文段 请求关闭连接 同时主机2进入 CLOSE_WAIT状态
**第四次挥手:**主机1收到主机2发送的FIN报文段 向主机2发送ACK报文段 随机主机1进入 TIME_WAIT状态 主机2收到主机1的ACK报文段以后 就关闭连接 此时主机1等待2MSL后依然没有收到回复 则证明Server端已经正常关闭 那么 主机1也可以关闭连接了
为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
---- 首先 MSL是最大报文生存时间 是任何报文在网络上存在到最长时间 超过这个时间报文将被丢弃
---- TCP的TIME_WAIT需要等待2MSL 当TCP的一端发起主动关闭 三次挥手完成后发送第四次挥手的ACK包后就进入这个状态 等待2MSL时间的主要目的是 防止最后一个ACK包对方没有收到 那么对方在超时后将重发第三次挥手的FIN包 主动关闭端接到重发的FIN包后可以再发一个ACK应答包 在TIME_WAIT状态时两端的端口不能使用 要等到2MSL时间结束才可以继续使用 当连接处于2MSL等待阶段时任何迟到的报文段将被丢弃
client发送完最后一个ack之后 进入time_wait状态 但是它怎么知道server有没有收到这个ack呢
因为网络原因 主动关闭的一方发送的这个ack包很可能延迟 从而触发被动连接一方重传FIN包 极端情况下 这一去一回 就是两倍的MSL时长 如果主动关闭的一方跳过TIME_WAIT直接进入closed 或者在time_wait停留时长不足两倍的MSL 那么当被动关闭的一方早先发出的延迟包到达后 就可能出现了类似下面的问题:旧的tcp连接已经不存在了 系统此时只能返回rst包2 新的tcp连接被建立起来了 延迟包可能干扰新的连接 这就是为什么需要等待2msl时长的原因
为什么连接的时候是三次握手 关闭的时候是四次挥手?
因为当server端收到client端的syn连接请求报文后 可以直接发送syn+ack报文 其中ack报文是用来应答的 syn报文是用来同步的 但是关闭连接时 当server端收到fin报文时 很可能并不会立即关闭socket 所以只能先回复一个ack报文 告诉client端 “你发的报文我收到了” 只有等到我server端所有报文都发送完了 我才能发送fin报文 因为不能一起发送 故需要四次挥手