【计网】从零开始明确TCP协议 --- 熟悉TCP报头结构并明确三次握手与四次挥 ...

打印 上一主题 下一主题

主题 1497|帖子 1497|积分 4491


   我依旧敢和生活顶撞,      敢在逆境里撒泼,        直面生活的污水,          永世乐意为新一轮的月亮和日落欢呼。            --- 央视文案 ---                

  
1 前情提要

前一篇文章我们讲解了UDP协议,UDP协议的结构很简单,维护链表结构的指针,报头指针和数据指针。与之对应UDP协议是不可靠的,没有重传机制,没有传送缓冲区。UDP协议是面向数据报的,接受者会一次性收到一份完整的数据报!
TCP协议就要更加的复杂一些,与之对应的就变得可靠!我们在应用层利用TCP协议举行通信时,不仅要创建套接字,还需要举行客户端connect创建连接,服务端accept获取连接;TCP是面向数据流的,还需要举行数据流的解析,判断是否读取到完整的报文结构!再来看下图:

TCP具有两个缓冲区:发送缓冲区和接收缓冲区,因此TCP协议也是支持全双工的!读写的策略本质是拷贝数据到缓冲区中,什么时候发送由操作系统举行考虑!接下来我们就来学习Tcp协议!
2 TCP报头的底子结构

TCP报头结构是如许的:



  • 源/目的端标语:这些字段指示了数据的发送进程与接收进程,即数据包的来源与去向。
  • 32位序列号/32位确认号:这两个字段用于管理TCP连接中的数据传输次序,确保数据的有序交付,具体细节将在后文详述。
  • 4位TCP头部长度:表示TCP头部的长度,以32位字(4字节)为单位盘算。因此,TCP头部的最大长度为15 * 4 = 60字节。
  • 6位标志位

    • URG:指示紧急指针字段是否有效,用于处置惩罚紧急数据。
    • ACK:确认号字段是否有效,用于确认已成功接收的数据。
    • PSH:提示接收端的应用步伐应立即从TCP缓冲区中读取数据。
    • RST:要求对方重新创建连接,携带RST标志的报文段被称为复位报文段。
    • SYN:用于发起连接请求,携带SYN标志的报文段被称为同步报文段。
    • FIN:通知对方本端即将关闭连接,携带FIN标志的报文段被称为结束报文段。

  • 16位窗口大小:该字段用于流量控制,将在后续部分举行详细说明。
  • 16位校验和:由发送端添补,接纳CRC校验。接收端对校验和举行验证,若校验失败,则认为数据在传输过程中受损。该校验和覆盖了TCP头部及数据部分。
  • 16位紧急指针:该字段标识紧急数据的结束位置,以便接收方可以或许识别并优先处置惩罚紧急数据。
  • 40字节头部选项:对于底子明确,这部分可以临时忽略,但它提供了对TCP协议的扩展功能。
应用层处置惩罚好数据放入缓冲区中,TCP协议会对数据举行封装。当TCP协议的接收缓冲区获取到报文时,会举行解包,将数据从报文中分离出来!为了可以或许将数据举行解包,就需要 4位TCP头部长度。当缓冲区有了完整报文时,会先读取前面的20字节,读取到一系列字段。其中的 4位TCP头部长度【0 ,15】就是代表整个报文的的长度。 4位TCP头部长度是有基本单位的(4字节),0-15代表0-60字节!总长度减去前20字节即可!
别的的字段我们接下来通过对TCP协议的可靠性的分析举行明确!
3 确认应答机制

3.1 什么是确认应答

日常生活中当我们面对面聊天时,我们可以通过对方的表情来判断对方是否听见了自己的表达。当距离拉远时,就很通过表情举行判断,那么你们决定利用听见就大喊“听见了”。通过对方喊出“听见了”,我们就可以或许确定对方接收到了我们的信息。类似如许机制就确认应答机制。

TCP协议中具有如许的机制!发送方向接收方发送数据时,接收方收到消息就发送一个应答,发送方接收到了就知道自己之前发送的消息对方收到了。而接收方此时还不知道对方有没有接收到,所以发送方这时也向接收方发送一个应答告诉接收方。那么如许就会不断不断的发送应答告诉对方我收到了!如许是不切实际的,生活中总要有一个人说最后一句话!也就是总要一条消息没有被应答!


  • 收到了应答就知道历史数据100%被对方收到了!这就是可靠性!
  • 假如应答没有成功传给对方呢?客户端就会认为数报文丢失了,就会重新再发送一次报文(超时重传机制)。
在正常的TCP通信过程中,客户端给服务器一个消息,服务端就给客户端一个应答。客户端不需要对这个应答做处置惩罚!这种应答就能说明历史消息已经转达!假如应答在发送过程中出现问题,客户端会自己举行处置惩罚,重新发送报文,这是另外一个机制了!
客户端和服务端都接纳确认应答机制,来包管两个朝向的通信的可靠性!这个机制是由操作系统完成的,所以利用TCP的代码中并不需要编写。
TCP有两种通信模式:


  • 客户端每次发送数据,都会立即接收到应答
  • 客户端发送多个数据时,一次性返回多个应答。
很显着方案二的模式更加高效!但是如许有一个问题,假如多个应答中有一个应答丢失,如何知道是哪一个应答丢失呢?所以一定要有标识应答的字段 — 32位序列号/32位确认号。确认序号是报文序号+1。当收到一个应答时,可以包管这个应答之前所以的数据都收到了!应答中只有报头结构,没有数据,确认序号被设置!
   有个问题?在这种场景中一个序号不就可以了吗?为什么需要报文序号和确认喜欢?应答中直接返回报文序号不就好了!
这个我们背面讲解
  3.2 确认序号和ACK标志位

假如只利用一个序号,那么就是忽略了服务器也可以给客户端发送消息,忽略了TCP通信的全双工性质!服务器发送应答时假如也想给客户端发送信息呢?此时肯定需要两个序号,分别代表发送的数据和发送的应答 ,这叫做捎带应答。这时应答和发送同时利用一个报头。
作为服务器来说,会收到客户端发送的各种各样的报文:创建连接的请求,端口连接的请求,确认报文,正常数据,确认+数据…。所以TCP协议要有处置惩罚差别类型报文的本领,即TCP的报文是有差别种别的。如何知道TCP协议的类型呢? 通过6位的标志位为来确定!
只要是确认报文,就要设置ACK位置为1,填好32位确认序号!

如何明确序号?

  • 起首对于发送缓冲区和接受缓冲区可以明确为一个char类型的大数组。
  • 数据从应用层拷贝到缓冲区中,缓冲区内数组的下标就自然可以代表序号了。
  • 发送时就可以根据数组下标当做序号举行发送消息!
  • 实际环境会复杂一点,可以先如许简单明确。
所以通信的双方,可以互相将数据带上序号来举行发送数据了!
4 超时重传机制

上面谈的都是报文成功发送过去,服务端收到了报文,并做出了应答。但是网络通信并不是百分之百会做到传输的稳定性的,所以可能会发生丢包的环境:报文丢包或应答丢包!此时客户端都不会收到应答,就不会知道历史消息是否成功的被接收了!超时重传机制就是为了解决这种问题。
超时重传机制很好明确:假如主机 A 在一个特定时间间隔内没有收到 B 发来的确认应答, 就会举行重发;
不管我们有没有发送成功数据 ,只要我没有收到来自对方的ACK,我就认为我的发送失败了!需要重新发送!
当应答丢包多次,那么主机 B 会收到很多重复数据。那么 TCP 协议需要可以或许识别出那些包是重复的包,并且把重复的丢弃掉。这时候我们可以利用前面提到的序列号,就可以很容易做到去重的效果
   注意,发送端发送报文的次序不一定是服务端接收数据的次序。这个很好明确。那么服务端接受到消息就很有可能是乱序的,但是数据是有次序的,所以为了服务的正常运用,需要对数据举行按序到达!所以对多个报文可以根据序号举行排序就可以,假如中间少一部分:比如1000,2000 , 4000 的数据到了,但是3000的没到,那么就先将1000, 2000的传给上层,等待3000再将4000一切交给上层。
  超时重传机制的等待间隔是动态的,由于网络状态是不稳定的,不能包管每次的传输速度是一致的,假如接纳较小的固定时间间隔,那么再网络较卡的环境下就有可能会造成大量的发送数据!反而降低的传输服从。接纳较大的固定时间间隔,那么就更会降低传输服从了!所以接纳动态的调节!根据网络环境关联!
为了包管无论在任何环境下都能比力高性能的通信, 因此会动态盘算这个最大超时时间:
   

  • Linux 中(BSD Unix 和 Windows 也是云云), 超时以 500ms 为一个单位举行控制,每次判定超时重发的超时时间都是 500ms 的整数倍.
  • 假如重发一次之后, 仍旧得不到应答, 等待 2*500ms 后再举行重传。
  • 假如仍旧得不到应答, 等待 4*500ms 举行重传. 依次类推, 以指数形式递增.。
  • 累计到一定的重传次数, TCP认为网络或者对端主机出现异常, 逼迫关闭连接
  5 连接受理机制

5.1 三次握手

TCP协议是面向连接流的,通信的底子就创建连接!所以创建连接的请求就十分的关键!在正常环境下TCP要经过三次握手创建连接!同样的,创建连接的请求是独特的类型,当标志位SYN设置为1时说明是要创建连接!
之前利用TCP举行编程的时候,我们会将服务端的sockefd设置为listen状态,然后客户端举行Connect创建连接,服务端举行accept接受连接。这其实就是三次握手的过程


  • 初始化与套接字创建:客户端和服务端均完成初始化操作,并创建套接字文件。服务端将套接字设置为监听模式。
  • 客户端发起连接:客户端实行Connect函数,向服务端发送SYN请求,并等待服务端的相应。发起三次握手
  • 服务端相应请求:服务端通过accept函数监听,接收到客户端的SYN请求后,返回一个SYN应答。
  • 客户端处置惩罚应答:客户端接收到服务端的SYN应答后,Connect函数实行完毕并返回,同时发送一个应答给服务端。
  • 服务端确认连接:服务端接收到客户端的应答后,accept函数实行完毕。完成三次握手
  • 连接创建成功:至此,客户端与服务端之间的连接成功创建。
这个过程中发生了三次传输,也就是三次握手!注意:Connect只是发起三次握手;accept不参与三次握手的过程,他只是将OS创建好的连接fd返回给服务端!
三次握手的过程可以利用一个非常幽默的例子举行明确:
   小明今天在前去教室的路上,看到了一个十分漂亮动人温柔优雅的女生小美,小明一见倾心,马上就去小美面前说:“很高兴熟悉你,我很喜欢你,可以做我女朋侪吗?”
小美见到小明帅气的脸庞,倒三角的身段,个性的穿搭。一下子也迷上了小明,就说:“好啊好啊,什么时候开始?”
小明激动地说:“就现在!”
  双方利用了最简洁的语言,完成了男女朋侪关系的确定!客户端和服务端三次握手就是如许一个过程!
最后一次的ACK不一定会被服务端接收到,但是只要发出了最后的ACK,就认为三次握手完成了!创建连接的本质就是在堵:堵最后一个ACK对方一定收到了!那不是太马虎了?其实不马虎,三次握手中就已经验证客户端可以收发消息,服务端可以收发消息,这就足够了!
当最后一次ACK丢包时,客户端并不知道丢包了,于是会正常向服务端发送数据,服务端收到数据,就知道了之前的ACK丢包了, 没有收到!此时会利用RST标志位发送应答,客户端就知道了需要重新举行创建连接!所以举行三次握手时不需要考虑最后一次的ACK是否成功,后续发送数据就会得到验证!RST实际中就是:

5.2 四次挥手

当连接断开时,客户端举行了close时,就会举行四次挥手:

四次挥手的过程利用一个简单例子举行明确
   小明与小美相处的不是很舒畅,小美看这个男生天天打游戏,不上进,于是想要分手,那么一定是要征求双方同意。需要我向跟你分手,你想和我分手,那么终极两个人就再无瓜葛!
  所以双方都会发送一次FIN请求!举行四次挥手


  • 客户端发送FIN请求本质:是告诉服务端客户端给你的数据已经发完了,没有数据再举行传输了(注意正常的ACK照旧会发送的)!我断开连接了!客户端可以调用shutdown接口关闭写端,那么还可以继续读取服务端发送的数据!
  • 服务端发送FIN请求:是告诉客户端给你的数据我都发完了,没有数据再写了!
四次挥手利用最小的通信资本,创建了断开连接的共识!双方都反面对方通信了!并且也知道对方不再和我举行通信了!
这里可以解决之前利用http的一个问题:当我们利用ctrl+c退出客户端步伐时,再次启动雷同端标语时会出现bind error,由于客户端退出来并不代表连接退出了,处置惩罚连接举行四次挥手是需要一定时间的,没有完成之前,连接是一直存在的!
5.3 为什么要三次握手

在内核数据结构中,是需要一个管理连接的数据结构的,所以维护管理连接时是由资本的!那么在三次握手时会创建连接结构体,四次挥手时会举行delete!
假如一次挥手就能创建连接,当客户端发生SYN大水时(伪造大量SYN请求举行创建连接),服务端就会创建出一堆的连接数据结构,如许就挂满了大量无用的连接,会浪费服务器的资源,终极可能会造成很大影响!两次接纳同理!
但是三次挥手如许看不是也怕SYN大水吗,其实这是一个机制的问题,三次挥手要求客户端发回ACK才会创建连接!那么客户端以后占用一定的资源!所以客户端就无法伪造大量的SYN请求举行SYN大水了!固然三次挥手也有其他的机制来避免SYN大水。一次两次挥手则是存在显着的BUG,会被利用!
三次挥手有以下长处:

  • 验证全双工:三次挥手可以验证网络的连通性,由于三次接纳中客户端和服务端都举行了收发数据!
  • 确认双方意愿:三次挥手可以包管双方都想要创建连接!可以达成一个共识!
  • 资本低:四次挥手和五次挥手等不外也是为了完成前两个目的!而三次握手时资本最低的!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

圆咕噜咕噜

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表