网站改版公司,西安官网seo公司,高质量的佛山网站模板,搜索关键词优化排名注#xff1a;TCP不是只有十个机制
TCP
可靠传输是tcp最为重要的核心#xff08;初心#xff09;
可靠传输#xff0c;并不是发送方把数据能够100%的传输给接收方
而是退而求其次
让发送方发送出去数据之后#xff0c;能够知道接收方是否收到数据。
一但发现对方没有…
注TCP不是只有十个机制
TCP
可靠传输是tcp最为重要的核心初心
可靠传输并不是发送方把数据能够100%的传输给接收方
而是退而求其次
让发送方发送出去数据之后能够知道接收方是否收到数据。
一但发现对方没有收到就可以通过一系列的手段来进行补救
1.确认应答
确认应答就是用来判断接收方是否能够收到数据。
发送方把数据发送给接收方之后接收方收到一个数据之后就会返回一个应答报文。
发送方如果收到了这个应答报文就知道自己的数据是否发送成功了。 在网络中可能会出现一些信息丢失的情况如下
A先发给B一个咱们下午去吃自助餐然后又发了一个咱们组队学习吧
B回应给好啊又发送一个滚吧。
正常的情况下A收到回复明白了咱们下午去吃自助餐但是不组队学习
但是不知道什么原因A先收到了滚吧在收到好啊就理解为咱们组队学习下午不吃自助餐 。
这样收到的回应的顺序不同造成的误解很使人困扰。在实际的网络传输中就也有可能会出现这样的后发先致的情况一个数据包在传输的过程中走的路径可能是非常复杂的不同的数据报走的不同的路线。
TCP解决上述个问题需要完成两个工作
1.确认应答报文和发送出去的数据能够对上号不要出现歧义。
2.确保在出现后发先致的现象下能够让应用程序这边仍然按照正确的顺序来理解数据。 TCP中的32位序号位和32位确认号位就会在发送信息时进行标记然后如果出现后发先致就让其等待至先发的到来。如下述例子
A先发给B一个咱们下午去吃自助餐标记为1然后又发了一个咱们组队学习吧标记为2
B回应给好啊针对1的确认序号1又发送一个滚吧针对2的确认序号2。
这样就通过序号了描述了数据的先后顺序。 此图只是粗略的形容了一下大概的工作流程实际中序号并不是按照这样一条两条来进行编号而是按照字节来编号TCP面向字节流 如图所示一个TCP包中一共有1000个字节的载荷数据。其中第一个字节的序号是1就在TCP报头的序号字段中写1.
由于一共是1000个字节最后一个就是1000但是1000这样的数据并没有在TCP报头中记录。TCP报头中记录的序号是这一次传输的载荷数据中的第一个字节的序号。其他字节的序号需要一次的推出。
在应答报文中就会在确认序号字段填写1001
因为收到的数据是1-1000所以1001之前的所有数据都被B收到了或者也可以理解为B向A要从1001开始的数据。 通过特殊的ack数据包里面携带的”确认序号“告诉发送方哪些数据已经被确认收到了.
此时发送方心中就有数了知道自己刚发的数据是到了还是没到。也就构成了可靠传输的核心部分。
TCP的初心是为了实现可靠传输 达成可靠传输的最核心的机制就是确认应答。 如何区分一个数据包是普通的数据还是ack应答数据 如图所示
当ACK这一位为1时表示当前的数据包是一个应答报文此时该数据包中的确认序号字段就能够生效。
这一位为0时表示当前数据包是一个普通报文此时数据包是一个普通报文。此时数据包中的确认序号字段是不生效的。
TCP这里的常见面试题通过确认应答为核心借助借助其他机制辅助最终完成可靠传输。
不是三次握手四次挥手保证了可靠传输这是建立连接的。 2.超时重传
确认应答描述的是一个比较理想的情况
如果网络传输过程中出现了丢包操作怎么解决
发送方肯定就无法接收到ACK。 为什么会出现丢包
网络如同现实生活中的公路一样错综复杂并且有很多的收费站
平常如果车流量不大的时候车会很快通过收费站很少出现堵车
但如果到节假日收费站肯定会出现堵车
网络中的收费站可以理解为是一些路由器/交换机
如果数据包太多了就会在这些路由器/交换机上出现堵车
但是路由器针对堵车的处理往往粗暴不会把这些积压得数据包都保存好而是将其中得大部分数据包之间丢弃掉这个数据包直接消失了在网络中。 丢包是一个随机得事情在上述tcp传输过程中丢包存在两种情况
1.传输的数据丢失了 2返回的ACK丢失了 发送方无法区分这两种情况所以无论出现哪种情况发送方都会进行重新传输。
第一次是丢失了重传一下试试很大概率能传过去
假设丢包的概率是20%两次都丢包的概率是4%重传就大幅度的提升了数据会被传输过去的概率重传操作是一个很好的丢包补救措施。 注引入了可靠性会付出代价。最明显的代价两方面
1.传输效率
2.复杂程度 发送方何时进行重传等待时间初始的等待时间是可以配置的。不同系统的时间不一定一样也可以通过修改一些内核参数来进行改变时间等待的时间也会进行动态变化每多经历一次超时等待时间都会变长
发送方发出数据之后会等待一段时间。如果这个时间之内ack到达了被视为数据到达。如果到达这个时间数据还没到就会触发超时重传
例如
A-B发了一条数据, 第一次,A等待ACK的时间,假设是50ms
此时如果达到50ms,还没有ack,A就重传. 当A重传的数据,还是没有收到ack,第二次等待的时间就会比第一次更长 拉长也不是无限拉长,重传若干此时,时间拉长到一定程度,认为数据再怎么重传也没用了就放弃 tcp连接(准确的说是会触发tcp的重置连接操作) 根据上图站在B的角度来看收到了两条一样的数据收到了重复的数据是否会给程序带来一些bug比如发一条收的时候收到了两条一模一样的数据。
TCP帮我们解决了这个问题TCP有一个接收缓冲区内存空间,会保存当前已经收到的数据以及数据的序号。接收方如果发现当前发送方发来的数据是已经在接收缓冲区中存在的收到过重复的数据接收方就会直接把后来这个数据给直接丢弃掉确保应用程序读的时候只能读到一条数据。 接受缓冲区不仅能进行去重还能进行重新排序。确保发送的顺序和接受的顺序是一致的。 3.连接管理
建立连接断开连接
三次握手和四次挥手
tcp这里的握手就是给对方传输一个简短的没有业务数据的数据包通过这个数据包来唤起对方的注意从而触发后续的操作。
握手这个操作不是TCP独有的甚至不是网络通信独有的计算机中的很多操作都会涉及到握手 TCP的三次握手TCP在建立连接的过程中需要通信双方一共”打三次招呼“才能完成建立连接的。 A想和B建立连接A就会主动发起握手操作实际开发过程中主动发起的一方就是客户端被动接受的一端就是服务器。
同步报文段就是一个特殊的TCP数据包没有载荷的不携带业务数据的应用层数据包
握手完成A和B记录了对方的信息构成了逻辑上的连接。
建立连接的过程其实是通信双方都要给对方发起syn,也要给对方反馈ack。一共是4次握手了但是中间两个可以合并成一次。 上图中的syn这一位为1表示这个报文段是同步报文段如果是1不是同步报文段。 三次握手是要解决什么问题?? TCP初心,是为了实现可靠传输” 进行确认应答和超时重传有个大前提,当前的网络环境是基本可用的,通畅的. 如果当前网络已经存在重大故障了,此时,可靠传输,无从谈起. 三次握手的核心作用一 确认当前网络是否是通畅的 三次握手核心作用二
要让发送方和接受方都能够确认自己的发送能力和接受能力均正常 三次握手核心作用三: 让通信双方,在握手过程中,针对一些重要的参数,进行协商
握手这里要协商的信息其实是有好几个的。 大家要知道, tcp通信过程中的序号从几开始,就是双方协商出来的(一般不是从1开始的) 每次连接建立的时候,都会协商出一个比较大的,和上次不太一样的值.| 上图中的客户端应用层和服务器端应用层是操作系统原生socket api对应的执行过程
右侧TCP层的LISTEN等类似的都是服务器的状态服务器这边的socket创建好并且把端口号绑定好此时就会进入listen状态。此时就允许客户端来建立连接。ESTABLISHED是客户端和服务器都会有的状态。
注 FIN叫做结束报文段。 建立连接一般都会是客户端主动发起的。
断开连接客户端和服务器都可以发起。 此时连接断开这个时候就相当于A和B都把对端的信息删除了。
和三次握手不同的是这里的四次挥手不一定可以将中间的两次交互合二为一
不一定的原因在于ACK的触发时机和FIN的触发时机是不同的。
ACK是内核响应的。B收到FIN就会立即返回ACK
第二个FIN是程序的代码触发的B这边调用了close方法才会触发FIN
从服务器到收到FIN同时返回ACK在到执行到close发起FIN中间的时间是不确定的。 像前面的三次握手,ACK和第二个syn都是内核触发的.同一个时机.可以合并. 这里的四次挥手ACK是内核触发的,第二个FIN是应用程序执行close触发的.时机不相同,不能合并.
那是否意味着,如果我这边代码close没写/没执行到,是不是第二个FIN就一直发不出去??(有可能的) 如果是正常的四次挥手,好聚好散”正常的流程断开的连接. 如果是不正常的挥手(没有挥完四次),异常的流程断开连接.(也是存在的)
TCP中有一个机制延时应答能够拖延ACK的回应时间。一旦ACK滞后了就会有机会和下一个FIN合并在一起。 如上图如果哪一方主动断开连接哪一方就会进入到TIME_WAIT
TIME_WAIT存在的主要意义防止最后一个ACK丢失 如果最后一个ACK丢失了从右边来看右边就会触发超时重传。
重新传送给左边FIN。
如果没有TIME_WAIT状态就意味着左边这个时候已经进入到CLOSED状态释放连接了。
此时重传的FIN没有人可以进行处理没有人能返回ACK了右边也永远收不到ACK关闭不了了。
左边使用TIME_WAIT状态进行等待等待的这个时间就是为了处理后续右边可能重传的FIN
此时有重传的FIN来了就可以正常返回ACK了。
右边的重传才有意义 TIME的等待时间
假设网络上的两个节点通信消耗的最大时间为MSL可自己配置的参数
那么TIME_WAIT的时间就是2MSL上限绝大部分的数据包不会到达这个时间 4.滑动窗口 TCP的可靠传输会影响到传输的效率。因为多出来一些等待ack的时间单位时间内能够传输的数据就变小了。
滑动窗口可以让可靠传输对性能的影响小一些。
TCP引入可靠机制导致传输效率是不可能超过没有可靠传输的UDP的。
TCP的效率机制都是为了尽可能减少两者之间的差距。
缩短确认应答的时间 如上图每收到一个应答报文再发下一个数据这个过程中等待时间比较长。 如上图进行批量传输数据不等待ack返回直接在发下一个数据。
批量传输也不是无限的进行传输。
存在一定上限达到上限统一等待ack。
不等待的情况下批量最多能发多少个数据这个数据量被称为窗口大小。 如上图
当前A-B是批量的发了四份数据.此时B也要给A回应四组ACK 此时A已经达到窗口大小,再收到ACK之前,不能继续往下发了. 需要等待有ACK回来了之后,才能继续往下发. 这里是怎么继续发的?是等待四个ack都回来了,在继续发四条?还是回来一个ack就继续发一个呢?回来一个ack,就立即继续发一个.
这里的直观效果看着就像这个窗口在往后滑动一样 TCP的初心是可靠传输上述滑动窗口中确认应答是可以正常工作的。
但是出现丢包的话怎么办
情况一 这种情况不需要任何重传。确认 序号表示的含义是当前序号之前的数据已经确认收到了。下一个你应该从确认序号这里继续发送。
如1001这个ack丢了但是2001ack到了。证明2001之前的数据都已经确认传输成功了包括了1001的情况。
情况二 主机A需要知道哪个数据丢了 主机B告诉主机A哪个数据丢了
如上图所示B下面一直返回下一个是1001就是给A说1001之前的都没有传给我并且无论当前传输的数据具体是几都在索要1001这个数据。
A收到了B的连续索要1001知道了这个数据之前的包丢了进行重传。
1001到达之后直接就返回了7001
上述的重传过程没有额外的冗余操作哪个数据丢了就重传哪个数据没丢的数据不需要重传(快重传滑动窗口下的超时重传的变种) 如果通信双方,传输数据的量比较小也不频繁,就仍然是普通的确认应答和普通的超时重传
如果通信双方,传输数据量更大,也比较频繁,就会进入到滑动窗口模式,按照快速重传的方式处理. 通过滑动窗口的方式传输数据,效率是会提升的. 窗口越大,传输效率就越大.(一份时间,等待的ack 更多了,总的等待时间更少了)
但是滑动窗口设置的越大越好吗
如果传输的速度太快,就可能会使接收方处理不过来了.此时,接收方也会出现丢包.发送方还得重传 TCP前提是可靠性.可靠性的基础上,再提高传输效率. 5.流量控制
站在接收方的角度反向制约发送方的传输速率
发送方发送的速率,不应该超过接收方的处理能力. 如图
数据到达B的系统内核中. tcp socket对象上带有接收缓冲区. A-B发的数据,就会先到达B的接收缓冲区.
B这边还有应用程序,就会调用read这样的方法,把数据从接收缓冲区中读出来,进一步的进行处理. (—旦数据被read了就可以从接收缓冲区删除了)
类似于生产者消费者模型 接收方每次收到数据之后,都会把接收缓冲区剩余空间大小通过ack返回给发送方.发送方就会按照这个数值来调整下一轮的发送速度.
接收缓冲区的剩余空间大小 根据16位窗口大小来进行划分的 并且TCP报头中,选项部分里有一项是叫做窗口扩展因子 通过扩展因子,就可以让窗口大小表示一个更大的值. 如图
接收缓冲区总的空间是4000收到1000数据之后,还剩3000. 于是就把3000放到应答报文中,告诉发送方了.
依据收到的3000确定了这一轮发送的窗口大小 假设在这个过程中,接收方的应用程序还没来得及处理任何数据呢, 此时收到一个数据,接收缓冲区的剩余空间就缩小—分 反馈0,意味着告诉A我接收方这边已经满了.你暂时先别发数据了.此时,A确实就要暂停发送
那么暂停多长时间
此时,虽然不传输业务数据了仍然会周期性的发送一个窗口探测包”并不携带具体的业务数据. 探测包就只是为了触发ack,为了查询当前接收方这边的接收缓冲区剩余空间. 6.拥塞控制
流量控制,是考虑的接收方的处理能力.不仅仅是接收方,还有你整个通信的路径.
通信过程中的任何一个节点处理能力达到上限都可能会对发送方产生影响影响到可靠传输。
拥塞控制就是考虑/衡量通信过程中的中间节点的情况 由于中间节点,结构更复杂,难以直接的进行量化.因此就可以使用“实验的方式,来找到个合适的值. 让A先按照比较低的速度先发送数据(小的窗口)如果数据传输过程非常顺利,没有丢包, 再尝试使用更大的窗口更高的速度进行发送.(一点一点变化) 随着窗口大小不停的增大达到一定程度,可能中间节点就会出现问题了.此时这个节点就可能会出现丢包.发送方发现丢包了,就把窗口大小调整小。此时如果发现还是继续丢包,继续缩小.如果不丢包了,就继续尝试变大
再这个过程中,发送方不停的调整窗口大小,逐渐达成动态平衡 如图
拥塞窗口拥塞控制下发送方应该按照多快的速度多大的窗口大小来进行传输
传输轮次TCP第几次发送数据
指数规律增长翻倍每次 网络拥塞丢包一但触发丢包就把窗口大小在缩小。重新开始前面的慢开始指数增长线性增长为了避免指数增长一下达到丢包的极限
注按照指数增长的过程中如果达到阈值就要从指数增长变为线性增长 流量控制和拥塞控制都是在限制发送方的发送窗口的大小
最终时机发送的的窗口大小是取流量控制和拥塞控制的窗口的较小值 7.延时应答
A把数据传给B,B就会立即返回ack给A正常 也有的时候,A传输给B,此时B等一会再返回ack给A延时应答
其本质上也是为了提升传输效率
发送方的窗口大小就是传输效率的关键
流量控制就是根据接收缓冲区的剩余空间来决定发送速率。如果可以使流量控制得到的这个窗口更大一些发送速率就会更快一些大也要在接收方能处理的极限之内
而延时应答就是给接收方更多的时间来读取接收缓冲区的数据此时接收方读取了比之前更多的数据之后缓冲区的剩余空间变大返回的窗口值也会变大。
如下假设
初始情况下,接收缓冲区剩余空间是10kb,如果立即返回ack,返回了10kb这么大的窗口.如果延时个200ms再返回,这200ms的过程中,接收方的应用程序的,又读了2kb, 此时,返回的ack,就可以返回12kb的窗口了. 8.捎带应答
在延时应答的基础之上进一步的来提高效率。 ack是内核立即返回的
response则是代码返回的
两者返回的时机不一样 由于tcp 引入了延时应答.上面的ack,不一定是立即返回,可能要等一会.在等一会的过程中,B就正好把response给计算好了.计算好了之后就会把response返回于此同时顺便就把刚才要返回的ack 也带上了.
这样就将两个数据合成称为一个数据
本来要传输两个数据包通过上述操作将两个包合并成一个得到更高的效率。
9.面向字节流
还有一个关键的问题,粘包问题(不是 tcp独有的,而是面向字节流的机制都有类似的情况) 目前,接收缓冲区中,这三个应用层数据包的数据,就是以字节的形式紧紧挨在一起的. 接收方的应用程序,读取数据的时候, 可以一次读一个字节,也可以读两个字节,也可以读N个字节...... 但是最终的目标都是为了得到一个完整的应用层数据包. B应用程序,就不知道,缓冲区里的数据,从哪里到哪里是一个完整的应用数据包了. 如何解决粘包问题? 核心思路:通过定义好应用层协议。明确应用层数据包之间的边界. 1.引入分隔符.
可以在输入的数据的时候加上特殊符号来进行分隔比如回车当读入到回车的时候证明这个数据是一个完整的单独的数据。 2.引入长度.|
在输入数据时加上各自字节的长度当读到长度时截止。 10.异常情况的处理
在使用TCP过程中如果出现意外怎样进行处理
1.进程崩溃
进程没了异常终止了.文件描述符表,也就释放了.相当于调用socket.close() 此时就会触发FIN,对方收到之后自然就会返回FIN和ACK,这边再进行ACK(正常的四次挥手断开连接的流程)TCP的连接,可以独立于进程存在.(进程没了TCP连接不一定没) 2主机正常关机
在进行关机的时候,就是会先触发强制终止进程操作.(相当于1)
此时就会触发FIN对方收到之后,自然就会返回FIN和ACK. 不仅仅是进程没了整个系统也可能关闭了.如果在系统关闭之前,对端返回的ACK和FIN到了,此时系统还是可以返回ACK,进行正常的四次挥手的.如果系统已经关闭了ACK和FIN迟到了无法进行后续ACK的响应站在对端的角度,对端以为是自己的FIN丢包了,重传 FIN.重传几次都没有响应,自然就会放弃连接.(把持有的对端的信息就删了)
3.主机非正常关机停电等
假设A和B A停电了
此时是一瞬间的事情,来不及杀进程,也来不及发送FIN主机直接就停机了.
站在B的角度,B不一定知道这个事情咋搞~~ 如果B是在发送数据(接收方掉电)发送的数据就会一直等待 ack .触发超时重传﹒触发TCP连接重置功能.发起“复位报文段 如果复位报文段发过去之后,也没有效果,此时就会释放连接了. 如果B是在接收数据(发送方掉电),B还在等待数据到达.等了半天没消息此时其实无法区分,是B没法消息这 还是A挂了 TC中提供了心跳包机制.(形象的比喻) 接收方也会周期性的给发送方发起一个特殊的,不携带业务数据的数据包.并且期望对方返回一个应答.如果对方没有应答.并目重复了多次之后.仍然没有,就视为对方挂了.
4.网线断开
当前假设,是A正在给B发送数据一旦网线断开 A就相当于就会触发超时重传-连接重置-单方面释放连接.B就会触发心跳包-发现对端没响应-单方面释放连接.