传输层协议Tcp详解----上

1.什么是传输层协议TCP

TCP 全称为 "传输控制协议( Transmission Control Protocol "). ⼈如其名, 要对数据的传输

进行⼀个详细的控制;TCP 是互联网传输层核心可靠协议,面向连接、有序无差错传输,通信前需三次握手建立连接,传输中进行确认应答、超时重传、流量控制与拥塞控制保障数据完整送达,通信结束通过四次挥手断开连接,以字节流形式收发数据,具备丢包重传、去重排序能力,适用于文件传输、网页访问等对数据完整性要求极;

由上图我们可以知道TCP协议位于传输层,由操作系统进行管理;

下图是TCP协议的报文结构,接下来我们将详细的学习它其中每一个字段的作用;

2.Tcp如何保证自己的可靠性(确认应答机制)

其实就是通过确认应答,即无论是服务器还是客户端在发送完消息之后,对端在收到消息之后要给发送端发送确认应答的消息,这样就能保证消息一定是发送成功了,即保证了自己的可靠性;而如果接收端始终不给发送端发送确认应答消息,发送端就会一直向接收端发送消息直到接收端收到消息之后发送确认应答,这样就不需要对确认再确认;

发送方发送的是报头+有效载荷,而接收端发送的确认应答则是一裸的TCP报头,并非我们想的只有一个1或者0,这很重要;

四位首部长度的作用:

首先虽然四位首部长度只占4个bit位,但是它的单位是字节,假设四位首部长度中的数字是5,呢么5*4=20个字节,表示报头的大小是20个字节,则报头没有选项;假设4位首部长度中的数字是6,呢么6*4=24,表示报头的大小是24,选项以上占20个字节,呢么选项字节则占4个字节;

3.32位序号和32位确认序号的作用

首先我们要知道在真正的网络场景中像之前呢种发送数据,确认,再发送数据,再确认的场景是很少的。因为这样的效率太低了,真实情况是直接发送大量数据然后发送大量的确认应答消息,如下图

在网络中同时发送好几条这样的数据,而确认序号就是为了对报文进行确认,这种发送方式才是Tcp真正的发送方式,而确认序号=序号+1,这是为了告诉发送端31之前的数据已经收到,41前的数据已经收到;与此同时因为网络发送数据是不稳定的,也就是先发送的报文可能后到,这就会导致报文的顺序是乱的,也是不可靠的,所以序号的意义也就多了一个可以保证报文在接收端的顺序;但是因为我们知道报文在发送给对端的时候,对端发来的应答是一个裸的报头,但是这样的话我们只用一个序号不就可以进行排序和确认应答了吗。为什么还需要有一个确认应答序号呢?

什么是捎带应答?

这是因为我们发送给对端数据,对端可能不止只是给我们发送一个确认应答的消息,也有可能会根据我们的发送的消息,给我们做回复,这种情况就是所谓的稍等应答机制,这种情况的出现也印证了报头中同时需要序号和确认序号的必要性;

4.TCP的16位窗口大小+流量控制

16位窗口大小是对端的接收缓冲区的剩余空间大小 ,作用是可以让我们的发送端进行流量控制;保证TCP的可靠性,也保证了减少浪费时间浪费空间的事件发生;而流量控制 != 减少发送,如果对端的16位窗口大小,也就是挺大的时候,不就可以加大流量了吗,反之在对端的接收缓冲区大小比较小的时候减少流量,这就是所谓的流量控制;从这个观点我们能知道接收缓冲区和发送缓冲区应该是有固定长度的,事实也正是如此;

5.接收和发送缓冲区的本质

Tcp的发送缓冲区的大小是确定的,发送缓冲区本身是一个char buffer[n] 的数组,而我们之前说的序号其实就是数组下标,也就是TCP其实对每个字节的数据都进行了编号,用来确认数据在数组中放置的位置的,这也就是为什么TCP是基于字节流的,因为它本身就是一个char buffer[n]类型的数组,而当我们的数组被写满的时候,或者为读空的时候,就会发生写阻塞或读阻塞,这个时候可以将网络和我们的用户层想象成生产者消费者模型,而我们的缓冲区就是交易场所;

6.超时重传/TCP丢包

丢包之后两种情况,①数据丢了 ②应答丢了

OS给发出去的数据设置了超时时间,如果时间到了还是没有应答,这个时候OS就知道发出去的数据已经丢了,主机A就会给主机B将刚才的数据进行重传,这种方式叫做超时重传;

但是主机A能否确认是自己的数据丢了还是对方发来的应答丢了呢?显然是不可以的,因为它只知道超时了,而数据以及应答在网络中的情况她一概不知,所以主机A其实连数据是否真的丢了都不知道,有的时候数据可能只是在某个路由器卡住了,但是超时时间到了,主机A只会认为是丢包了,它只会重发,但是这个时候不就会在主机B收到相同的报文?这就得依靠我们之前的序号了,它能做到去重;

所以这个超时时间的设定不能太短了,也不能太长了,但以为网络的情况是变化的,所以这个超时时间的设定也应该是变化的;

而这个功能OS是如何做到的呢?有很多的方法,将这些数据设置为小堆,每次时钟中断的时候拿出来对应的堆顶对应的数据结构发生重发;

**呢么这个超时时间在linux中是怎么设置的呢?**或者说是怎么确定的呢

理想状态下需要设定一个最小时间,确保报文的确认应答能在此时间内返回。但该超时时间会随网络环境变化而改变:
超时时间设置过长,会降低整体重传效率;
超时时间设置过短,容易触发不必要的频繁重复发包。

为适配不同网络环境、兼顾通信性能,TCP 会动态计算超时重传时间。Linux、BSD Unix、Windows 系统均遵循统一规则

超时时间以 500ms 为基础单位,实际超时值均为 500ms 的整数倍;
首次超时未收到应答,等待 2×500ms 后重传;
仍无应答则等待 4×500ms 再次重传,超时时间按指数形式递增;
当重传次数累计达到上限时,TCP 判定网络故障或对端主机异常,强制关闭连接

7.Tcp标志位作用

首先我们应该知道服务器收到的报文的类型是不一样的,有的报文可能是为了断开连接、有的是发起连接、有的是发送数据,而服务器想要知道他们的类型就要通过Tcp标志位了,它里面存放着报文的类型;

ACK:是一个确认标志位,ACK设置为1才能真的确认自己是一个确认报文;

FIN:是连接断开标志位,为1表明这个报文是断开连接的报文

SYN: 是建立连接标志位,SYN位为1表示是这个报文时建立连接的报文;

8.三次握手和四次挥手

上图就是三次握手的过程

①首先是客户端向服务端发送建立连接SYN置为1的报文,状态就成为了SYN_SENT状态->发送连接状态,

② 服务端收到之后,给客户端也发送了一个SYN置为1,以及ACK(确认信号)标志位为1的报文,自己的状态只要收到ACK就变为了SYN_RECV,即建立连接收到状态;

③之后客户端收到服务器的想要建立连接的请求报文以及自己的请求建立连接的确认报文,它的连接已经建立成功,状态也转为了ESTABLISHED状态,表明以及成功建立连接,并给服务器发送了确认应答报文;这个过程就是三次握手;

我们发现第二次握手的时候服务器即给客户端发送了一个确认应答,又给客户端发送了一个建立连接的请求,这两个完全可以分成两次进行,但是因为服务器一直是开着的,所以他一定会给客户端发送确认应答,所以发送请求连接的报文时捎带上确认应答,因为确认应答也只是发送一下报头,也就是捎带应答,故而三次握手本质上就是四次握手;

而捎带应带只发一条 TCP 报文,把头部里的 ACK 标志位 和 PSH/SYN/FIN 等标志位 同时置 1数据 + 应答 装在同一个包里一起发

值得注意的是当三次握手通信成功之后,我们的操作系统才会给accept()返回对应的套接字,也就是说accept不参与三次握手的过程,只是在等三次握手成功,而listen则是在三次握手之前就已经建立成功,等待客户端的通信请求;

而客户端的connect的作用是触发客户端发送ACK报文给服务器,一旦客户端和服务器的三次握手成功,connnet成功,并返回;所以connnect也不参与三次握手的过程;

为什么要三次握手呢?

①双发有想要建立通信的意愿

②验证双方在正式通信之前,双方的通信信道是可以通信的

而三次握手也不一定会成功;比如当最后一次ACK丢了的时候,我们的服务端就没有成功建立通信,这个时候服务器就会抛异常,如

上图是四次挥手的过程,比三次挥手简单一些,首先是客户端向服务器说我要跟你断开连接,服务器说好的,然后服务器向客户端发送说我也要跟你断开连接,客户端也说好的;

四次挥手之所以是四次,是因为断开连接需要征得双方同意,这是因为TCP是全双工的;而如果当客户端想要跟服务器断开连接的时候,服务器也想要和客户端断开连接,这个时候四次挥手也可以变成三次挥手;

如果我们的客户端向服务端发送了关闭连接的FIN报文,并且服务器也回复了ACK,但是服务器并没有关闭自己向客户端的信道,还想给客户端发送信息,可是这个时候客户端已经完全关闭了,既关闭了自己的写端也关闭了自己的读端,这个时候如何读到客户端给自己发来的信息呢?

这个时候我们只用让客户端和服务器的关闭连接不再使用close,而是使用shutdown就完全不影响了,因为我们可以选择是关闭写端还是读段;就是实现了半通信,应用场景很少;

呢我想知道如果客户端关闭和我的连接,我作为服务器客户端就必须也要关闭和他的连接吗?如果我一直不关闭,或者每个客户端跟我关闭连接的时候我都不关闭和他的连接会造成什么后果呢?

当客户端主动关闭连接时,服务器并非必须立刻关闭对应连接,但从工程实践角度看,如果不关闭会导致严重后果:每个TCP连接在服务器端都占用一个有限的文件描述符(Linux默认通常为1024或65535),若服务器检测到客户端关闭(如read返回0)后不调用close,这些文件描述符将永不释放,最终耗尽导致accept失败、新客户端无法连接;同时每个连接的内核内存(如struct sock等)也会持续泄漏,长期运行可能引发系统不稳定或OOM;此外,服务器端TCP状态会卡在CLOSE_WAIT,这是明确的应用层bug信号。极少数例外情况(如专线长连接)也不能依赖不关闭的行为。因此,服务器必须在检测到客户端关闭后,及时调用close(必要时先shutdown再close)释放资源,这是编写稳定高并发网络服务的基本准则。

关于time_wait

当一个连接绑定了地址和端口号之后,一旦主动断开连接,便会进入TIME_WAIT保护状态,这个时候socket也没有被释放,所以端口号和地址还在被占用,这个一般用来保护我们客户端的,但是在服务器中,所谓的TIME_WAIT状态处于四次挥手的时候,客户端发给服务器ack之后的等待时期,如果此时客户端在发完ack之后直接断开连接,关闭套接字,很可能会造成OS对之前在网络中之前阻塞的报文,即游离报文的造成混乱处理,因为不确定服务器此时收到了你的ack,如果没收到你此时就已经关闭,服务器就会再次发起fin,但是已经在网络中找不到你了,这个时候就会造成脏连接残留;

总结一下为什么要进行time_wait呢?

而处于time_wait的时候连接还没有close,而端口号和还在被占用;但是作为服务器TIME_WAIT 会占着端口不放 → 服务器重启立刻再绑同一个端口会绑定失败(端口被占用)地址端口重用(SO_REUSEADDR) 就是专门用来:无视 TIME_WAIT 占用,强行立刻复用端口启动服务器。它本身是socket的一个选项;

9.什么是连接

相关推荐
Oll Correct3 小时前
实验二十四:网络地址与端口号转换NAPT
网络·笔记
星星也在雾里3 小时前
内网服务对外访问:cpolar 内网穿透完整教程
网络·tcp/ip
老詹图解IT3 小时前
统信 UOS 登录界面转圈闪退/卡登录等常见原因及处理
linux·服务器·网络
轻颂呀3 小时前
进程间关系和守护进程
linux·网络
QH139292318803 小时前
R&S®SMBV100B 矢量信号发生器 5G/Wi-Fi/GNSS 主力源
网络·科技·嵌入式硬件·集成测试·信息与通信
皮卡蛋炒饭.3 小时前
传输层协议TCP
服务器·网络·tcp/ip
JSMSEMI114 小时前
JSM13N50F 500V N 沟道功率 MOSFET
大数据·网络·人工智能
盟接之桥4 小时前
制造业场景 | 电子数据交换(EDI)软件|AS2协议
大数据·网络·安全·汽车·制造
小子想咋滴4 小时前
ospf不规则区域划分
网络