TCP 连接
TCP 报文格式
此处介绍建立或者断开TCP连接时,需要了解的TCP报文段首部字段含义:
序列号 seq:占4个字节(32位),用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号;序列号 seq 就是这个报文段中的第一个字节的数据序号。
确认号 ack:占4个字节(32位),期待收到对方下一个报文段的第一个字节的数据序号;序列号表示报文段携带数据的第一个字节的序号;而确认号指的是期望接收到下一个字节的序号;因此当前报文段最后一个字节的序号 +1 即为确认号。
TAG | Description |
---|---|
URG | 紧急指针标志,为 1 时表示紧急指针有效,为 0 则忽略紧急指针 |
ACK | 确认序号标志,为 1 时表示确认号有效,为 0 表示报文中不含确认信息,忽略确认号字段 |
PSH | PUSH 标志,PUSH 标志为 1 的 TCP报文段,接收方在接收到该 TCP报文段 以后,应尽快将这个报文段交给应用程序,而不是在缓冲区排队 |
RST | 重置连接标志,用于重置由于主机崩溃或其他原因(拒绝非法的报文段或连接请求)而出现错误的连接 |
SYN | 同步序号标志,用于建立 TCP 连接,在连接请求中,SYN=1,ACK=0;而连接响应中,SYN=1,ACK=1 |
FIN | 断开连接标志,用于断开 TCP 连接,在断开连接请求中,FIN=1,ACK=0;而断开连接响应分两个步骤(需要传完全部数据),第一部分:FIN=0,ACK=1,第二部分:FIN=1,ACK=1 |
TCP 三次握手
第一次握手:建立连接时,客户端发送同步 SYN 包(seq=x)到服务器,并进入 SYN_SENT 状态,等待服务器确认;
第二次握手:服务器收到同步 SYN 包,必须返回给客户端一个确认 ACK(ack=x+1),同时自己也发送一个同步 SYN(seq=y),即 SYN+ACK 包,此时服务器进入 SYN_RECV 状态;
第三次握手:客户端收到服务器的 SYN+ACK 包,向服务器发送确认 ACK 包(ack=y+1),此包发送完毕,客户端和服务器进入 ESTABLISHED(TCP连接成功) 状态,完成三次握手 。
TCP 三次挥手
第一次挥手:客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为 seq=u(等于前面已经传送过来的数据的最后一个字节的序号加 1),此时,客户端进入 FIN-WAIT-1 状态。 TCP规定,FIN 报文段即使不携带数据,也要消耗一个序号;
第二次挥手:服务器收到连接释放报文,发出确认报文 ACK=1,ack=u+1,并且带上自己的序列号 seq=v,此时,服务端就进入了 CLOSE-WAIT(关闭等待)状态。服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个 CLOSE-WAIT 状态持续的时间;
第三次挥手:客户端收到服务器的确认请求后,此时,客户端就进入 FIN-WAIT-2 状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据);
第四次挥手:服务器将最后的数据发送完毕后,就向客户端发送连接释放报文 FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为 seq=w,此时,服务器就进入了 LAST-ACK(最后确认)状态,等待客户端的确认;
四次挥手后的等待(确保服务端收到第四次挥手TCP报文):客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是 seq=u+1,此时,客户端就进入了 TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过 2MSL(最长报文段寿命)的时间后,客户端才会撤销相应的 TCB(Thread Control Block)线程控制块,进入 CLOSED 状态。而服务器只要收到了客户端发出的确认,立即撤销 TCB,进入 CLOSED 状态,结束这次 TCP 连接 。可以看到,服务器结束 TCP 连接的时间要比客户端早一些 。
常见面试题
【问题1】为什么建立连接的时候是三次握手,端口连接的时候却是四次握手?
(因为断开连接时,需要传完当前连接剩余的数据,而建立连接时,并不需要此步骤)
答:因为当 Server端 收到 Client端 的SYN连接请求报文后,可以直接发送 SYN+ACK报文。其中 ACK报文 是用来应答的,SYN报文 是用来同步的。但是关闭连接时,当Server端收到 FIN报文 时,很可能并不会立即关闭 SOCKET,所以只能先回复一个 ACK报文,告诉 Client 端,“你发的FIN报文我收到了”。只有等到我 Server 所有的报文都发送完了,我才能发送 FIN报文,因此不能一起发送。故需要四步握手。
【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
(为了确保 Server 收到了 ACK 报文段)
答:虽然按道理,四个报文都发送完毕,我们可以直接进入 CLOSE 状态了,但是我们必须假想网络是不可靠的,有可以最后一个 ACK报文 丢失。所以 TIME_WAIT 状态就是用来重发可能丢失的 ACK报文。在 Client 发送出最后的 ACK报文时,该ACK报文丢失。Server如果没有收到 ACK报文,将不断重复发送 FIN报文段。所以 Client 不能立即关闭,它必须确认 Server 接收到了最后的 ACK报文。Client会在发送出 ACK报文之后进入到 TIME_WAIT 状态。Client 会设置一个计时器,等待 2MSL 的时间。如果在该时间内再次收到 FIN报文,那么 Client 会重发 ACK报文 并再次等待 2MSL 的时间;所谓的 2MSL 是两倍的 MSL(Maximum Segment Lifetime),MSL 指一个片段在网络中最大的存活时间,2MSL 就是一个发送和一个回复所需的最大时间。如果等待了 2MSL 之后,Client 没有再次收到 FIN,那么 Client 推断 ACK报文 已经被 Server 成功接收,则结束 TCP 连接。
【问题3】为什么不能用两次握手进行连接?
(假设两次握手,可能发生两种异常情况)
答:三次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
现在把三次握手改成仅需要两次握手,考虑计算机 Server 和 Client 之间的通信,假定 Client 给 Server 发送一个连接请求(SYN=1)分组,Server 收到了这个分组,并发送了确认应答(SYN=1,ACK=1)分组。按照两次握手的协定,Server 认为连接已经成功地建立了,可以开始发送数据分组 。但此时可能会有两种异常情况:
①.Client 的请求分组(SYN=1)在传输中被堵塞(并非丢失)的情况下,由于请求分组在网络中滞留的时间过长,Client 很久得不到 Server 的应答分组,将会发起第二个请求分组(SYN=1),Server 收到了第二个请求分组,即刻返回确认分组(SYN=1,ACK=1),建立连接;但第一个请求分组(SYN=1)并没有丢失(对于 Client 而言此请求分组已经丢失或者失效),在连接释放以后的某个时间才到达 Server,此时 Server 会误认为是 Client 又发出的新的建立连接请求,于是又返回确认分组(SYN=1,ACK=1),又建立了连接,但是 Client 实际上并没有发出请求分组(SYN=1),不会理睬 Server 的确认分组(SYN=1,ACK=1),也不会向 Server 发送数据,而 Server 却以为新的连接已经建立,并一直等待 Client 发送数据,这样就白白浪费了 Server 的许多资源 。
②.Server 的应答分组(SYN=1,ACK=1)在传输中被丢失的情况下,Client 将不知道 Server 是否已准备好,不知道 Server 建立什么样的序列号,Client 甚至怀疑 Server 是否收到自己的连接请求分组。在这种情况下,Client 认为连接还未建立成功,将忽略 Server 发来的任何数据分组,只等待连接确认应答分组 。而 Server 在发出的分组超时后,重复发送同样的分组 。这样就形成了死锁 。
【问题4】如果已经建立了连接,但是客户端突然出现故障了怎么办?
(保活计时器)
TCP连接设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接 。
TCP 连接的更多相关文章
- TCP连接的建立和终止
TCP的简要要说明 标签(空格分隔): TCP 网络编程 Linux 面试 在此输入正文 一.TCP是什么 TCP全称传输控制协议(Transmission Control Protocol).TCP ...
- 简述TCP连接的建立与释放(三次握手、四次挥手)
在介绍TCP连接的建立与释放之前,先回顾一下相关知识. TCP是面向连接的运输层协议,它提供可靠交付的.全双工的.面向字节流的点对点服务.HTTP协议便是基于TCP协议实现的.(虽然作为应用层协议,H ...
- HTTP的RST包与WinHttp延迟关闭TCP连接
一.RST包也常见于断开TCP连接 几个月前用wireshark抓HTTP包发现有的网络通信在结束的时候没有使用四次握手,而是直接使用RST包.如: 在TCP协议中RST表示复位,用来异常的关闭连接 ...
- 一个完整的TCP连接
当我们向服务器发送HTTP请求,获取数据.修改信息时,都需要建立TCP连接,包括三次握手,四次分手. 什么是TCP连接? 为实现数据的可靠传输,TCP要在应用进程间建立传输连接.它是在两个传输用户之间 ...
- 查看 Apache并发请求数及其TCP连接状态
查看 Apache并发请求数及其TCP连接状态 (2011-06-27 15:08:36) 服务器上的一些统计数据: 1)统计80端口连接数 netstat -nat|grep -i "80 ...
- tcp连接listen的backlog剖析
TCP连接中,最重要的是连接TCP连接上,两个方向之间的各个状态及各个系统调用与状态之间的关系.往往可以以两种图表示,第一种是状态转换图,第二种是连接时序图.如下: 状态图: 时序图: ...
- 计算机网络(11)-----TCP连接的建立和释放
TCP连接的建立和释放 概述 TCP运输连接的建立和释放是每一次面向连接的通信中必不可少的过程,运输连接有三个阶段:连接建立,数据传送和连接释放. TCP连接的建立 如图所示,假定A主机是客户端程序, ...
- 查看 并发请求数及其TCP连接状态【转】
服务器上的一些统计数据: 1)统计80端口连接数netstat -nat|grep -i "80"|wc -l 2)统计httpd协议连接数ps -ef|grep httpd|wc ...
- TCP连接的三次握手和四次解散过程
客户端和服务器在使用TCP连接传输数据的过程中,需要经过三次握手建立连接和四次握手断开连接操作. 具体如下图所示 上图描述了TCP连接从建立到断开的详细过程,以下就其中的具体报文细节展开讨论. 在TC ...
- 传输层(2)-TCP连接的建立和终止、TIME_WAIT状态
1.TCP连接的建立和终止 1)三路握手 客户端发送一个SYN(同步)分解,告诉服务器客户将在连接中发送的数据的初始序列号. 服务器发送确认客户的SYN(ACK),同时自己也得发送一个SYN分节,它含 ...
随机推荐
- python协程爬取某网站的老赖数据
import re import json import aiohttp import asyncio import time import pymysql from asyncio.locks im ...
- 1.8V升3V芯片,1.8V升3.3V升压芯片方案
两节干电池由于耗电量电压会降低,无法长期稳定的输出3V或者3.3V供电,直接两节干电池会供电电压不稳,影响后面电路稳定.两节干电池的供电电压在1.8V-3.2V左右 1.8V升3V升压芯片方案, 如P ...
- kettle数据质量统计
1.利用Kettle的"分组","JavaScript代码","字段选择"组件,实现数据质量统计.2.熟练掌握"JavaScrip ...
- (07)-Python3之--函数
1.定义 函数:实现了某一特定功能. 可以重复使用. 例如: len() 功能:获取长度.input() 功能: 控制台输入print() 功能:输出 语法: def 函数名称(参数 ...
- spring boot 启动 开启注解 加载 bean
业务描述:创建一个cache类然后交给spring 管理. @Component @Scope("singleton") public class Cache { public C ...
- 使用nodejs构建Docker image最佳实践
目录 简介 准备nodejs应用程序 创建Dockerfile文件 创建.dockerignore文件 创建docker image 运行docker程序 node的docker image需要注意的 ...
- FlightGear 从输出所省略的额外重寻址溢出
2020-12-27 在龙芯Fedora28上编译 FlightGear 2019.1.1 时遇到 从输出所省略的额外重寻址溢出 错误,错误信息如下: [ 98%] Linking CXX execu ...
- LIS的优化
二分优化 在求一个最长不上升自序列中,显然其结尾元素越小,越有利于接其他元素,对答案的贡献也就可能会更高 那么我们可以用low[i]去存长度为i的LIS结尾元素的最小值 因此我们只要维护low数组 对 ...
- 洛谷P4317
Description 定义 \(sum(i)\) 表示 \(i\) 的二级制中 1 的个数 给定一个 N,求 \(\prod_{i=1}^N sum(i)\) Solution 显然是数位 DP 考 ...
- js--数组的find()和findIndex()方法的使用介绍
前言 阅读本文前先来思考一个问题,面对一个非空数组,你如何快速对数组进行遍历,如何快速找到数组中第一个我们需要关注的数据元素,并且如何知道该元素在数组中对应的下标索引,可能用for循环遍历,然后判断元 ...