计算机网站建设,网站建设选择本地,网站建设注意点,著名的深圳网站建设文章目录一、TCP协议二、TCP工作机制1.确认应答2.超时重传3.连接管理三次握手四次挥手一、TCP协议
我们的TCP协议相比于UDP协议复杂不少#xff0c;今天我们就来一起学习一下TCP协议报文和原理 首先我们报头第一行里的端口号和UDP的端口号是一致的#xff0c;都是用两个字节… 文章目录一、TCP协议二、TCP工作机制1.确认应答2.超时重传3.连接管理三次握手四次挥手一、TCP协议
我们的TCP协议相比于UDP协议复杂不少今天我们就来一起学习一下TCP协议报文和原理 首先我们报头第一行里的端口号和UDP的端口号是一致的都是用两个字节来表示。 32位序号和32位确认序号 在这里先不给大家解释等会我们再将TCP确认应答原理时会给大家讲到。 4位首部长度 正是因为这个首部长度存在我们的TCP的报头长度是可变的而我们的UDP报头长度是8个字节固定死的首先我们需要明白我们选项之前的长度是固定的20字节而我们首部长度可以调节的就是选项长度我们首部长度的单位是4字节选项长度等于首部长度 - 20字节如果我们的首部长度是6那么TCP报头就是24字节(选项相当于是4字节)。 **保留(6位): ** 我们这里的保留六位是为了以后扩展考虑的因为我们的网络协议是一件成本较高的事情就拿UDP来说报文长度是2字节因此一个包最大是64KB如果我们想让它兼容更大一些的长度理论可行但是实际操作极高但是如果我们引入了保留字我们后面TCP引入了新功能就可以使用这些保留字不仅对报头结构影响极小而且老设备也不需要升级也可兼容。 这个我们在后面讲原理的时候会介绍到。 16位窗口大小16位紧急指针 这些我们在后面会介绍到16位窗口和我们的滑动窗口和流量控制原理有关。 16位校验和 和我们的UDP校验原理相同CRC,MD5,SHA1 选项 选项(option),这个是对TCP一些功能扩展和TCP一些属性进行解释说明的。
TCP报文 TCP报头 TCP载荷(payload)载荷也就是我们的数据。
二、TCP工作机制
我们的TCP相比于UDP是一个比较复杂的协议也包含很多机制我们主要学习10大核心机制
1.确认应答
TCP的特点中有可靠传输的特性确认应答就是实现可靠传输的核心机制。大家还需要明白我们这里的可靠指的不是我们发送方百分百能将数据发送到接收方而是尽可能的发过去即使没有发过去我们的发送方也能够知道。 比如我们有这样一个场景一个宿舍中的A同学和B同学要通信。 我们这里的不上就称之为应答报文也叫ack(acknowledge). 当A同学收到不上的时候就可以知道我们上号这个消息B同学已经看到了(证明没有丢包)如果我们一段时间后没有收到ack证明我们的消息大概率不见了(也就是丢包)。 TCP可靠传输主要就是靠这个确认应答机制来保证的我们A给B发消息B收到之后就会返回一个ackA收到这个应答之后就证明我们的数据顺利到达了(没有丢包)。 上述的通信是比较简单的单一通信我们来看一个稍微复杂一点的。 同学A可能会连续发多条消息发第二条消息时不需要等待第一个消息的应答我们的B同学收到消息立马回复我们在网络通信时很有可能发生后发先至因为我们的网络环境是错综复杂的很有可能发的晚的消息先到的情况。 上面的情况是正常的情况那么我们来看一个不正常的情况。 因为这种后发先至的情况我先收到了上后收到了不上这样我们的应答错乱后表示的含义就截然不同了。 首先网络上后发先至这种情况是客观存在无法避免的我们应该考虑的是如何应对这种情况所带来的异义。 我们采取的办法是给传输的数据和应答报文编号。 当我们引入序号后即使出现先发后至的情况消息的顺序即使乱了我们通过序号也可以明确将每条应答报文与其对应了。 我们任何一条数据(包括应答报文)都是有序号的确认序号只有应答报文有是否为应答报文取决于ACK这个标志位是否为1如果为1证明是应答报文如果是0表示不是应答报文。 我们实际上的TCP序号并不是简单的12这种方式编号我们TCP是面向字节流的我们的TCP序号也是按照字节来编号的。 假设我们的一条数据长度是1000个字节我们的数据是由1开始的此时我们第一个字节编号就是1第二个字节编号就是2依次但是我们前1000个字节都是属于同一TCP报文因此我们TCP报头里记录的序号就是第一个字节的序号也就是1。 当我们发送第二条数据序号就是1001了我们的TCP字节序号是依次增加的起始字节序号是上一个数据的最后一个字节我们TCP报头只需写TCP头一个字节序号即可在根据TCP报文长度即可知道TCP的每一个字节的序号。 我们应答报文里的确认序号中的1001就是刚才尾字节1000基础1的结果1001所表示的含义有两个: 1.小于1001的数据都已经确认收到了 2.发送方接下来应该从1001这个序号开始发送数据
结论 TCP可靠传输最主要是通过确认应答机制保证的我们不仅可以让发送方清楚的知道是否传输成功并且通过序号和确认序号对多组数据进行了详细的区分。
2.超时重传
我们刚才在讨论确认应答的时候只是在一个理想的传输场景下讨论的那如果在传输过程丢包了呢? 首先丢包有两种情况: 1. 发送的数据丢了 2.应答报文ack丢了站在我峨嵋你发送方的角度这两种情况都认为是丢包了正在因为这种丢包的可能性发送我们TCP就引入了重传机制我们在丢包的时候就要重新发一遍相同的数据那么如何判断是丢包还是ack正在返回路上? 我们TCP直接引入一个时间阈值在发送数据后就会开始倒计时等待ack如果时间超过时间阈值也没收到ack统一认为丢包。 超时重传 接收方在一定时间没有响应发送方就重新发送一份相同的数据。 时间阈值 超时时间具体是多少这个我们不具体讨论是多少根据场景业务而定是可配置的。 这种情况比较形象发送方发送的数据丢包了在一定的时间后重新传输一次然后收到ack之后就视为一次成功的传输。 但是当ack丢包时对于我们主机B而言1 -1000的数据接收了两次这种情况就比较麻烦了但是我们TCP对于重复的数据传输具有去重功能我们TCP存在一个发送缓冲区和接收缓冲区接收缓冲区相当于是接收方操作系统内核的一段内存我们在网络编程的时候学习的socket的对象中都有一个接收缓冲区我们主机B的网卡接收到数据之后将数据放到主机soekct对象对应的接收缓冲区中我们可以将这个缓冲区想象成一个优先级阻塞队列我们根据序号可以将数据进行去重排序如果有相同的数据就将后到的数据丢弃排序就可以应对我们的后发先至情况。 结论 由于我们去重与排序机制的存在发送方只要发现在一定时间阈值内ack没有到达就会重新发一份数据数据即使重复乱序我们的接收方都可以处理去重和排序机制都依赖TCP报头的序号。 相信有一些善于思考同学又会问了要是我们重传的数据有丢包了呢? 首先我们丢包是一件概率比较低的事件连续重传丢包的概率更低因此我们在重传到一定次数后就不会再死磕就会认为网络出现故障TCP就会尝试重置连接如果重置还是无效就会彻底断开连接。 TCP的可靠传输 TCP的可靠传输通过 确认应答 和 超时重传机制保证的两者相互配合共同保证了TCP的可靠性。
3.连接管理
连接在不同的场景表示不同的含义在我们TCP协议这里表示的是维护一些信息(四元组)的空间。 我们TCP建立连接并不是指通过一根线将两者连接起来而是将这两部分信息维护好简单来说A要能通过这部分信息找到BB能通过这部分信息找到B我们称保存好这部分信息的空间为连接删除这部分信息称之为断开。
三次握手
我们仍然拿出A同学和B同学刚上大学A同学和B同学想通过游戏加深一下感情但是又不知道对方玩什么游戏于是有了以下的场景: 首先A向B发出了询问然后B回应了A此时双方都知道了B玩王者农药但想要一起组队玩王者农药B需要明确A是否也玩于是B又发送了一次请求这时候A知道了B玩B知道了A也玩这个时候他们才能一起上号打游戏相当于建立连接成功。 我们把上述过程的每次通信形象的称为一次挥手但实际上我们有两次是可以合并成一次的。 我们所谓的三次握手的本质上是四次交互双方各自需要发送一个建立的请求然后收到一个ack实际上是有四次的信息交互但是中间两次是可以合并的因此就构成了三次握手。 如果不合并可以吗? 不可以如果我们从三次变成四次就会多封装分用一次成本更高就好比宿舍倒垃圾本来可以一个大袋子一次性倒一个是用两个小袋子分两次倒。
两次握手可以完成建立连接吗? 如果少了最后一次握手站在A的角度他已经知道了B玩王者农药但是站在B的角度他不知道A玩不玩王者农药。 有的同学可能会说A能问你A肯定玩呀虽然这个情况也有可能但是TCP这里不适用因为三次握手还有一个重要作用验证通信双方各自的发送和接收能力是否正常 比如我们两个人在打王者农药组队开麦A和B能够顺利交流需要有两个保证就是A和B的麦和音响都是好的。 第一次通信当B听到你可以听到吗? B知道了 A的麦是正常的B的音响是正常的。 A什么都不知道。 第二次通信当A听到可以你呢, B知道了A的麦是正常的B的音响是正常的。A知道了A的麦和音响以及B的麦和音响都是正常的。 第二次通信之后A以及知道了双方都满足了条件但B知道的信息还不全需要进行第三次通信。 第三次通信当B听到可以时证明我们A和B都知道了自己的麦和音响和对方的麦和音响是正常的可以正常交流了。 三次握手的作用 1.让通信双方建立相互的认可 2.验证双方的发送与接受能力是否正常 3.在握手的过程双方协商一些参数。 我们客户端主动给服务器发送的建立连接请求称为SYN同步报文段. 这些都是TCP的状态不同的TCP状态主要体现我们的TCP在干什么三次握手中我们主要学习两个重要状态 1.LISTEN服务器状态表示我们的服务器以及转杯就绪随时可以与客户端建立连接。 2.ESTABLISHED这个状态我们客户端服务器都有当我们进行两次握手后我们的客户端就已经认为进行成功建立连接于是进入了ESTABLISHED状态我们的服务器只有当三次握手进行完毕后才认为成功的建立了连接进入了ESTABLISHED状态当我们成功建立连接之后就可以进行通信了。 上述描述的三次握手一次性记住不太容易大家需要记住主要的流程
四次挥手
握手和挥手都是形象的叫法指的是客户端服务器之间的交互四次挥手指的是通信双方给对方发一个断开连接的请求在各自给对方一个回应。 这里我们同样是A同学和B同学打了一下午王者农药输了一下午 这里需要注意我们在断开连接的过程中中间两次通常是不能合并的。 我们三次握手之所以中间两次可以合并是因为它两是属于同一时机的具体来说三次握手的三次交互过程是系统内核完成的服务器内核收到了syn之后会立即发送ack也会立即发送syn。 这就好比于我们在同一家店铺买东西我们的三次握手中间的两次就相当于是同一时间段在一家店铺买的两样东西所以可以通过一个包裹发送这两样东西而我们四次挥手中间两次则是在不同的天数买的比如2月9号买了个牙刷2月11买了个牙膏则不能够通过一个包裹必须通过两个包裹发送。 我们的FIN发起不是有内核控制的而是我们客户端调用socket的close方法(进程退出)才会触发FIN我们服务器的ack是有内核控制的收到FIN之后立即返回ack而我们服务器的FIN是我们服务器执行到socket的close方法(或进程退出)才会触发FIN。 因此大家注意到我们服务器ack和FIN之间只有一个时间差的而这个时间差的大小由我们的代码所决定我们可以发开我们之前写的TCP客户端服务器回显服务器看一看。 我们可以看到这里的break决定着循环结束而这里的break能够执行到取决于我们的hasNext为false因就是流对象读到了EOF(文件结束标记)这里能读到EOF是因为内核收到了客户端发送来的FIN数据报虽然我们的客户端程序没有显示的写close方法但是当我们客户端进行退出的时候也会执行socket close会触发FIN。 当我们的循环执行结束之后会执行到finally里的close方法相当于我们服务器给客户端发送的FIN我们上述代码里循环结束后立即FINack与FIN之间的时间间隔相对就比较短也就有可能包裹成一个但是如果时间间隔比较长就不可以了比如这样: 我们的代码在close之前进行了一系列操作这样我们的FIN和ack时间间隔就比较久了也就无法合并成一个了。 同样的我们断开连接中的FIN在报头中也有标志FIN为1证明是断开连接的请求报文。 我们TCP四次挥手当中也有许多状态我们这里重点学习两个TCP状态 1.CLOSE_WAIT 出现在被动连接的一方等待关闭(等待socket调用close方法)大家需要注意的是建立连接的过程中一定是客户端主动发起请求断开连接可能是客户端也可能是服务器。 TIME_WAIT 出现在主动发起断开请求的一方法这里我们客户端是主动断开的一方当客户端进行TIME_WAIT状态时客户端认为四次挥手已经挥完了这里的TIME_WAIT要保持TCP状态保持一会不要立即释放。 为什么我们的TIME_WAIT要等待一会不要立即释放连接? 因为我们最后一个ack虽然已经发出去了但是仅仅是发出去了到没到我们得打一个问号万一这个ack丢包了呢我们TIME_WAIT会在发完ack之后等如果没有接收到重传的FIN就认为最后一个ack没有丢包然后释放连接。 站在我们服务器角度来说当我们ack发送了之后进入TIME_WAIT状态时相当于是四次挥手已经完成了一样没有客户端的活了虽然看起来完了但是是建立在一切顺利的前提下如果出现了丢包等情况客户端就没有完成工作我们的TIME_WAIT就是这些工作但的保证。 那么TIME_WAIT保持多久才真正释放呢? 我们这里等待的时间为2MSL 如果TIME_WAIT维持了2MSL都没用收到重传的FIN就认为我们的ack顺利到达了。 那么MSL指的又是什么呢? 指的是互联网上两个结点之间消耗传输时间的最大时间。至于这个MSL通常大概是60s在这里大家需要注意我们这里的MSL无论如何定义都不可避免一些特殊情况因此我们的MSL相当于是一个经验值绝大多数情况下数据包传输时间都不会超过MSL。