传输层--TCP协议详解(一)

目录

TCP协议

TCP传输的可靠

发送应答机制

超时重传机制

TCP头部结构

总结

TCP连接管理机制

三次握手和四次挥手

三次握手

四次挥手

三次握手和四次挥手和套接字的关系

TCP协议

传输层协议主要有两个:TCP协议和UDP协议,TCP协议是面向字节流、连接、可靠的,而UPD是面向数据报、不可靠的。

使用TCP协议的双方必须先建立连接,才可以进行数据的传输并且双方都必须给建立的连接分配响应的内核资源,以管理连接的状态和数据的传输。TCP连接是全双工的,也就是连接的双方可以同时进行读写操作,在通信完成之后,双方必须断开相应的连接来释放掉对应的系统资源。

TCP传输的可靠

我们使用TCP听过最多的可能就是TCP传输是可靠的,那么为什么TCP传输是可靠的呢?

再这之前先谈谈网络中的不可靠。

我们知道的是我们平常在家和朋友聊天是通过网络进行的,这之间的数据就需要通过长距离的传输来到达对方的网络中,那么在这个长距离的传输中,就有可能会发生各种各样的问题,从而造成数据的丢失,所以TCP就是为了解决这种问题的。

发送应答机制

首先TCP采用了发送应答机制,也就是发送端发出的每个TCP报文都必须得到对方的应答,才认为这个报文传输成功了。

该机制是根据TCP报头中的32位序号和32位确认序号来摆正的,但是需要注意的是发送应答机制只能保证的是接收方确实收到了一个TCP报文。

超时重传机制

超时重传机制是发送端在发送一个TCP报文之后,会启动一个定时器,如果在规定时间内没有收到对方的应答,那么就会重新发送该报文。

这中间就会产生我们常见的丢包问题,丢包一般分为两种:一种是发送的数据报文丢失了,接收端也就收不到,相应的也就没有应答产生了。另一种丢包就是接收方收到了报文,也发送了响应,但是在发送过程中丢失了。

需要我们注意的是,这两种丢包所产生的本质问题就是发送发收不到对应的应答,所以发送方是无法分辨是哪一种情况造成的,它只知道的是在规定时间内没有收到应答,就进行超时重传。

最后我们可能对这个定时器感到好奇,超时重传机制的等待时间一般是多久?

在Linux下为了保证能有较为高效的通信,一般是动态的修改等待时间的,例如首次是500ms,超过500ms后就会重传一次,然后等待的时间就是2*500ms,如果还得不到应答,下此超时重传等待的时间就是4*500ms,以此类推,但是当重传到一定次数后,TCP就不会进行重传了,就会认为是网络或接收端出现异常,然后关闭连接。

TCP头部结构

TCP头部字段如下图所示:

  1. 16位端口号:告知主机该报文段是来自哪里(源端口)以及传给哪个上层协议或应用程序(目的端口)的。进行TCP通信时,客户端通常使用系统自动选择的临时端口号,而服务器则使用知名服务端口号。
  2. 32位序号:一次TCP通信(从TCP连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号。假设主机A和主机B进行TCP通信,A发送给B的第一个TCP报文段中,序号值被系统初始化为某个随机值ISN(Initial SequenceNumber,初始序号值)。那么在该传输方向上(从A到B),后续的TCP报文段中序号值将被系统设置成ISN加上该报文段所携带数据的第一个字节在整个字节流中的偏移。例如,某个TCP报文所传输的数据是字节流中的第1000-2000字节,那么该报文中的序号之就是ISN+1000,从B-A的TCP报文的序号之也是如此。
  3. 32位确认号:用于对另一方发送来的TCP报文的响应。值是收到的TCP报文序号加1。
  4. 4位头部长度:表示的是该TCP头部字段的长度,4位表示最大值是15,所以TCP头部最长是60字节。
  5. 16位窗口大小:是TCP进行流量控制的一个手段,它能告诉对方的TCP接收缓冲区中还能存放多大字节的数据,以起到控制数据发送的速度。
  6. 16位校验位:是发送发填写的,表示接收端对TCP报文执行相应算法来检测TCP报文是否在传输过程中损坏,是TCP可靠性的一个关键点。
  7. 16位紧急指针:表示的是一个偏移量,需要配合标志字段当中的URG字段统一使用。
  8. 6位标志位。

URG标志:表示紧急指针是否有效。

ACK标志:表示确认还是否有效,

PSH标志:提示接收端应用程序应该立即从TCP接收缓冲区中读取数据,为后序到来的数据提供空间.

RST标志:表示需要对方重新建立连接,一般把带RST标志的TCP报文称之为复位报文。

SYN标志:表示请求建立一个连接,一般把带SYN标志的TCP报文称之为同步报文。

FIN标志:表示通知对方本端要关闭连接了,一帮把带FIN标志的TCP报文称之为结束报文。

TCP如何决定将有效载荷交付给应用层的某一应用?

        首先我们知道的是,TCP的上一层就是应用层,当PC和PC进行数据传输时,一般都是某一应用到某一应用的传输,并且我们知道的是应用层的每一个应用都有对应的端口号,所以TCP报头中也包含么源端口号和目的端口号(内核中使用哈希维护了端口号与进程ID之间的映射关系,所以传输层可以通过端口号快速的得到对应的端口号)。

分析一下32位序号和32位确认号的意义

上面说了32位序号是一次TCP通信过程中一个传输方向的字节流的每个字节的编号。

在通信过程中是并行的,所有每个报文在网络中传输的路径可能是不同的,所以到达目的端的顺序也就被打乱,并且报文的有序性也是TCP可靠的一种保障,所以32位序号就是用来保证有序性的。

例如:发送端发送3000字节的数据,每次只能发送1000字节,此时就需要发送三次

            第一次的32位序号就是1,第二次的就是1001,第三次的就是2001

            当目的端收到了保温之后,就会根据32位序号进行重排就能得到完整的一个报文。

32位确认号,说的是用作对另一方发来的TCP报文的响应,并自动+1

表示的就是,当我收到了32位序号为1的报文,该报文中就包含了1000字节的数据,也就表示我收到了1---1000的字节数据,并返回给发送发报文中的32位确认号改为1001.

一方面表示的是我收到了1---1000字节的数据。

另一方面表示我下次想要的数据是从1001开始的。

此时我们就会想这其中的某一段报文丢失了怎么办?

还是以上面的例子分析,假如1001-2000的报文丢失了,也就是接收端没有收到,那么接收端在对报文重排时就会发现只有1---1000和2001---3000的报文,而没有1001---2000的报文,而我们所说的32位确认号时是返回上次接收到的序号加1,此时我们收到了1---1000,理应的确认号就自动加1,变为1001,但是1000-2000的没有收到,虽然受到了2001---3000的,但是此时接收端返回的确认号还是1001.。

这样就可以让发送方知道了我在1000之后的数据有丢失,就可以对1000之后的数据进行重传。

总结

  • 32位序号的作用是,保证数据的按序到达,同时这个序号也是作为对端发送报文时填充32位确认序号的根据。
  • 32位确认序号的作用是,告诉对端当前已经收到的字节数据有哪些,对端下一次发送数据时应该从哪一字节序号开始进行发送。
  • 序号和确认序号是确认应答机制的数据化表示,确认应答机制就是由序号和确认序号来保证的,并且可以通过序号和确认序号还可以判断某个报文是否丢失。

TCP连接管理机制

我们知道TCP是面向连接的,这样就保证了我们的服务器的接收缓冲器就指挥存放和该连接的相关信息了,如果不是面向连接的话,同时有多个客户端和服务器进行数据交互是,就会造成服务器的接收缓冲区产生冲突。

所以我们在TCP通信的时候要先建立对应的连接之后才能保证数据通信的可靠。

在上述就存在一个问题,我们的服务器一般都是存在大量的连接的,所以服务器不得不对这些连接进行管理。

  • 首先可以组织一个描述连接的数据结构,这个结构中包含了该连接的相关属性
  • 当和一个新连接建立连接时,就给该连接创建一个结构变量并填充相应字段,然后插入到管理连接的结构中
  • 当和一个连接断开时,只需要将该连接节点从数据中删除并删除相应的资源即可

三次握手和四次挥手

三次握手

在连接管理机制中谈到TCP是面向连接的,每次通信前都需要建立连接,这个建立连接的过程称之为三次握手的过程。

在上图中client是客户端,server是服务端,当客户端想要和服务端建立连接,客户端会主动的向服务端发送建立连接请求,下来先介绍三次握手

  • 第一握手是客户端向服务端发起建立连接请求,其发送报文中的SYN被置为1,也就是请求建立连接
  • 第二次握手是服务端收到了客户端建立连接的请求后,首先给客户端返回其请求的响应,然后也对客户端发起建立连接的请求,返回报文中的SYN和ACK被置为1,这两个操作是在同一个报文中返回的
  • 第三次握手是客户端收到服务端报文后,知道服务端收到了自己建立连接的请求并想和自己建立连接,最后对服务端进行对应的ACK响应

此时我们可能有疑问的是为什么是三次握手,而不是四次甚至更多以及最后客户端发送给服务端的ACK丢失了怎么办?

首先我们需要知道的,这三次握手中,在客户端发送最后一次ACK的前提是前两次信息交互的成功,但是并不能保证最后一次ACK被服务端收到,如果服务端没有收到该响应,那么该连接也是失败的,所以如果添加了四次五次的ACK,我们都不能保证最后一次ACK能被百分百成功接收,所以到底是几次握手实际上是要看优点

首先可以肯定的是三次握手是

  • 验证全双工通信的最小成功并能保证通信的流程性
  • 也可以防止单机对服务器的攻击

一次握手行不行?

         一次握手肯定是不行的,因为如果只需客户端向服务端发送建立连接请求就完成连接建立的话,那么就可能出现无数次不同客户端向服务端发送建立连接的请求,就有可能把服务端搞垮(因为服务端需要对每一个客户端建立一个对应的数据建构,来实现对该连接的管理) 

那两次握手行不行?

        如果我们只需要两次握手的话,我们客户端向服务端发送了连接建立请求,然后服务端对其进行响应和发送建立连接的请求时,客户端可能收不到该请求(在网络中丢失了),那么客户端没有收到想要的响应,服务端也不知道自己的请求对方是否收到了,此时服务端如果盲目的建立连接管理的话,那么面临的问题和一次握手面临的问题是一样的。

最后

        三次握手需要保证的是不能让服务端误认为自己和某些没有建立连接的客户端建立了连接,而导致服务端维护了一些不存在的通信连接

        也就表明了三次握手实际上保证的是连接是断在客户端的而不是断在服务端的,因为客户端时单个的,其内部没有过的连接,而服务端不一样,其内部维护了大量的连接和很多的请求,这就需要服务端的空间资源被充分利用。

        还有就是当最后一次握手发生了丢包,客户端会误认为自己和服务端建立了连接,但是服务端没有收到最后一次握手所返回的 ACK响应,也就不会和客户端建立对应的连接,所以在一定的时间内:1.服务端在一定的时间内没有收到该客户端发送第三次握手,就会重新给客户端发送第二次握手的过程。 2.客户端给服务端发送数据,发现自己没有和服务端建立连接,就会再次发送建立连接的请求。

四次挥手

        当服务端和客户端之间不想通信时,就需要断开连接,但是断开是双方共同的事情,需要双方都同意。

还是以上述的方式为例分析四次挥手的过程。

  • 第一次挥手:客户端向服务器发送断开连接的请求,报文中的FIN被置为1
  • 第二次挥手:服务端收到客户端发来的断开连接的请求后,对客户端进行响应
  • 第三次挥手:服务端也向客户端发送断开连接的请求,但是需要注意的是服务端的断开需要建立在没有数据给客户端的时候。
  • 第四次挥手:客户端收到断开连接的请求后进行响应

但是还有需要注意的是服务端在回应客户端断开连接请求时,可以把应答和发送断开连接的报文整合为一个,此时四次挥手就可以理解成三次挥手,但是需要开启TCP延迟确认机制

三次握手和四次挥手和套接字的关系

套接字和三次握手的关系

  • 在客户端向服务端发起建立连接请求前,服务器需要进入listen状态,也就需要调用listen函数
  • 服务器进入listen状态时,就可以正常接收连接了,客户端向服务端发起连接,客户端调用connect函数(只负责发起三次握手,不参与建立的过程)
  • 当服务器和客户端成功完成了三次握手时,服务端需要调用accept函数来获取新连接
  • 当二者成功建立好连接时,双方就可以调用recv/send函数进行通信

套接字和四次挥手的关系

  • 客户端发起断开连接请求,就是客户端主动调用close函数。
  • 服务器发起断开连接请求,就是服务器主动调用close函数。
  • 一个close包含两次挥手,通信双方都要调用close,也就对应四次挥手。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值