【牛客网C++服务器项目学习】-Day11-TCP基本原理

项目学习地址:【牛客网C++服务器项目学习】

day 12

TCP的通信:

1.TCP通信的过程

  • TCP协议作为传输层的协议,承担的任务是实现不同主机之间端-端的通信。在应用层上的协议,如http、ftp协议都是通过TCP协议完成可靠传输的。在我们使用例如,xftp这类软件进行文件传输时,看不见的背后是每一次进行传输,都会在通信的双方之间建立TCP连接,TCP通信的过程大致是这样的:

    • 建立连接:三次握手的过程。

      • 第一次握手:客户端发起连接。客户端会向服务端送请求连接的TCP报文。请求连接的TCP报文中不包含数据,仅仅是发送连接请求。在这份TCP报文中设置了SYN=1标志位,这样服务端在众多TCP报文中能够识别到这份报文是想建立连接。此外,这份报文中还初始化了一个clien_isn初始序号,用于初始化服务端的TCP报文的ACK序号。(TCP报文由下一层的IP协议承担输运)。

      • 第二次握手:假设客户端请求连接的TCP报文顺利地被服务端接收到了之后,如果服务器这边还能继续新建一条TCP连接(一个服务器能够拥有的TCP连接数量是有限的),那么服务器会为这条TCP连接分配一块缓存资源和变量,并向客户端回复一条TCP报文。和第一次握手的请求报文中的信息不一样:首先,报文的SYN=1标记,代表这是同意连接;然后报文中的ACK = client_isn + 1;然后会初始化服务端的server_isn发送给客户端,用于初始化客户端的ACK 序号。

      • 第三次握手:假设服务端同意连接的TCP报文顺利地被服务端接收到了之后,客户端经过检查,确认这是我之前发起连接得到的回信。客户端也开始为这次TCP连接分配缓存和变量资源,此外客户端还会给服务器发送一份TCP报文,这份回复报文的意义在于:客户端需要告知服务端,正确接收到了你的回复,现在我们开始通信把。基于此,这份报文中需要包含的信息:SYN置为0,表示连接建立,不用再请求了;ACK序号 = server_isn + 1(序号要对得上才代表这次连接是正确的)。同时,第三次握手可以携带数据,发送给服务端。

img

  • 进行传输:确认了身份,建立了连接之后的通信双方便可以顺畅的进行通信了。但是网络世界是错综复杂的,建立了连接只是通信的一部分,TCP协议还使用了一些技术手段保证通信的持续、稳定。

    • 重传机制:服务器(客户端)迟迟没有回复消息怎么办?这便是重传技术的用途。重传技术发展至今,比较主流的有超时重传、快速重传、SACK、D-SACK

什么时候选择重传?

  - 超时重传:通信的双方都有一个定时器,每次发送一条TCP报文后,便开始计时,如果计时器时间走完,还没有收到回复消息,重复发送一次之前的TCP报文。计时器定时的时间通过复杂的计算。如果超时重发的数据,再次超时后,超时时间会加倍。
  - 快速重传:超时重传机制的弊端在于重发的效率有点低,反应比较呆。快速重传机制是当接收数据的一方,重复接收一个数据的**ACK**序号回复次数达到**3次**,那么系统就判定此时有数据发送失败或者对方收到不回复,继续重传

重传哪些数据?

  * SACK:我们思考一个问题:TCP是怎么保证数据传输的顺序正确的呢?在之前的网络模型总结中,我们知道TCP传输时会对从应用层获取的数据进行分段,同时对每一个分段分配对应顺序的序列号,这个序列号也即TCP报文头部的sequence。对于TCP传输的接收方,每正确接收一个序号对应的数据报,会在内部记录。如果发送方能够知道接收方接收了哪些数据,也就知道哪些数据是没有被正确接收的,重传接收方没有得到的数据即可。

这就是SACK的基本原理,选择性确认。通信的双方在TCP报文头部字段中寻找一个SACK的东西,可以将缓存的地图发送给发送方,这样发送 方就可以知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据。在 Linux 下,可以通过 net.ipv4.tcp_sack 参数打开这个功能(Linux 2.4 后默认打开)。

  - D-SACK在原理上和SACK并无太大区别,D_SACK是将重复接收的数据报告知发送方,目的为了让发送方得知发出去的包是丢了还是接收方回应的ACK丢了。

- 流量控制:

发送方不能无脑的发数据给接收方,要考虑接收方处理能力。 如果一直无脑的发数据给对方,但对方处理不过来,那么就会导致触发重发机制,从而导致网络流量的无端的浪 费。 为了解决这种现象发生,TCP 提供一种机制可以让「发送方」根据「接收方」的实际接收能力控制发送的数据量, 这就是所谓的流量控制

讲到流量控制,那就要先讲一下滑动窗口了

什么是滑动窗口呢?

对于通信的发送方来说,一份待发送的数据,存在四种状态:已发送已确认被接收的、已发送但是未被接收的、未发送的、不可用的。在操作系统中,维护了一个缓冲区窗口用于存放【已发送但是未被接收的】的数据,在发送的过程中,这个缓冲区的数据会不断更新,看起来就像是在待发送的数据段上进行滑动一样,故得名滑动窗口。

滑动窗口机制是在流水线技术上的完善和更新。早期设计的TCP协议只能让发送方将数据分组一个发完等到确认后,再发送新的数据分组。引入流水线技术后大大提高了网络线路的利用率和传输效率。

但是像滑动窗口这样,一次性发送一个窗口的数据,带来了新的问题:这一组的数据如何确定被正确接收?这里TCP协议带来了两个解决方法:GBN(go back N回退N步)、选择重传。

  • 断开连接:四次挥手的过程。接收方和发送方都可以主动终止连接。

    • 第一次挥手:客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN 报文,之后客 户端进入 FIN_WAIT_1 状态。

    • 第二次挥手:服务端收到该报文后,就向客户端发送 ACK 应答报文,接着服务端进入 CLOSED_WAIT 状态。 客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态。

    • 第三次挥手: 等待服务端处理完数据后,也向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态。

    • 第四次挥手:客户端收到服务端的 FIN 报文后,回一个 ACK 应答报文,之后进入 TIME_WAIT 状态 。服务器收到了 ACK 应答报文后,就进入了 CLOSED 状态,至此服务端已经完成连接的关闭。 客户端在经过 2MSL 一段时间后,自动进入 CLOSED 状态,至此客户端也完成连接的关闭。

2.TCP的头部结构

img

  • 端口号:源端口和目的端口不多讲了。TCP头部的端口号和IP头部的IP地址形成了TCP确定通信双方的四元组

  • 序列号:TCP报文中数据的ID标识,序列号是按照数据分割的顺序进行排列的。第一个序列号的生成是随机的,目的是保证不要和之前的旧的,还在网络中飘荡的TCP报文冲突

  • 确认应当号:收到数据后给予对方的答复,接收方的ACk和对方的SEQ是关联的

  • 首部长度:可选项,一般为空

  • 6个标志位:只讲重要的

    • ACK:表示确认应答号是有效的。除了三次握手的第一次握手是0之外,之后的报文都得是1

    • RST:该位为1的话,表示TCP连接出现异常需要中断

    • SYN:请求建立连接。三次握手的报文中会出现这个标志位

    • FIN:拆除连接。四次挥手的报文中会出现这个标志位

  • 窗口大小:用于流量控制的字段。

  • 校验和:用于检查数据在发送过程中是否出现损坏。

3.TCP的重点一:三次握手

4.TCP的重点二:滑动窗口

5.TCP的重点三:四次挥手

未完待续,今天因为私事,学习记录没能整理好。除了自己写TCP的相关知识,我还写了进程的并发socket程序。在研究这个老师说的换行符‘\0’问题,然后我发现read函数也值得深究。待我搞明白这两点后会更新的

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值