计算机网路学习整理:传输层tcp协议

上章计算机网络的学习整理中整理了Http协议的内容,今天的文章中整理一下tcp协议。html

文章中部分图片来自于网络,侵删算法

首先介绍一下tcp协议, tcp一种可靠的,面向链接的服务,它为端与端之间的进程通讯提供了可靠的数据传输功能,经过流量控制,序号,确认和定时器等功能,tcp可以讲数据按序正确的从原进程传递到目标进程中。缓存

多路复用以及多路分解

多路复用以及多路分解是由网络层提供的主机到主机交付服务延伸到为运行在主机上的应用程序提供进程到进程的交付服务。一个进程(做为网络应用的一部分)有一个或多个套接字(socket),它至关于从网络向进程传递数据和从进程向网络传递数据的门户。将运输层报文段中的数据交付到正确的套接字的工做称为多路分解(demultiplexing)。而在源主机中从不一样套接字中收集数据块,并为每一个数据块封装上首部信息从而生成报文段,而后将报文段传递到网络层,全部这些工做称为多路复用(multiplexing)。服务器

从上面概念来看,多路复用以及多路分解就是一个对称关系的概念。接下来看下多路复用以及多路分解在传输层封装的报文段中的表现:网络

  • 端口号为16bit范围数字,大小在[0-65535],其中0-1023为周知端口号,不容许用户使用,如Http(80),FTP(21)等等

可靠数据传输原理

咱们在开发时候都知道TCP是一个可靠的传输协议,那么为何是可靠的呢?这个可能不少人并不了解。首先咱们来试想一想看可能会发生的问题:并发

  • 问题一:分组数据出错了该怎么处理呢?
  • 问题二:如何去保证按序传递数据呢?
  • 问题三:分组数据丢失了怎么办?

这些问题在数据传输中确定时会遇到的,那么该怎么解决这些问题呢?socket

自动重传请求协议(ARQ)

首先看看第一个问题,发生情境多是底层物理部件时候发生问题,致使了分组数据中有概率使一个比特数据从0变成了1。如何处理呢?在《计算机网络-自顶向下》中举了一个情景,我以为挺好:在打电话中,咱们在正常状况就正常对话就能够了,若是对方忽然说话声音听不清了,那么咱们就会让他重复一下上次说的话。那么在第一种问题情境中,咱们也可使用这种方式来处理,这种基于重传的可靠数据传输协议叫自动重传请求协议(ARQ)tcp

在ARQ中包含三种方式处理比特差错的状况:性能

  • 差错检测:提供一种机制来使接收方检测到比特发生差错,如(奇偶校验)。
  • 接收方反馈:对发送方发来的数据进行反馈,接收方返回结果给发送方时候带上"确定确认"(ACK)和"否认确认"(NAK)。
  • 重传:接收到由差错分组的时候,发送方从新发送分组数据。

这三种方式是按序发生的,当发送方发出数据的时候,接收方在接收到的同事进行差错检测,若是出现问题,那么接收方在答复的时候,在数据中带上NAK,反之带上ACK。发送方在拿到响应数据的时候,若是收到NAK时候,则进行重传。这里还得考虑一个问题,万一接收方的反馈也被物理部件影响返回彻底错误的结果了怎么办呢?既然发生了,那么咱们重发一次分组不就行了么,不是ACK的答复,都按照NAK来处理,其实不就处理好了么?经过这种方式是能解决问题,可是可能会形成一个问题:因为发送方不清楚接收方是否收到了数据,因此发两次给接收方可能形成冗余分组的问题。学习

如何却解决冗余分组的问题呢,TCP中会对每个分组带上序号,这样接收方能够去判断是重复数据仍是初始数据,若是接收方最近收到了相同序号的分组,那么就是重复数据了。而且,经过序号的方式,接收方在收到数据的时候可不只能够处理重复数据的问题,也能处理数据顺序的问题,接收方能够按照序号对失序的分组集进行重组传递给接收方应用程序,那么问题二情境也就天然而然解决了。

最后看下问题三,分组数据丢失了怎么办?可能发送方的分组数据丢了没到达接收方手里,也可能接收方返回的响应数据丢了,那么这个时候该怎么处理呢?这个问题其实很简单,咱们针对每一个分组数据设置一个定时器不就完了么。在定时器规定时间内没有获得响应数据,发送方就进行重传的操做就行了。

经过ARQ协议就可以保证数据的可靠传输,可是效率也是须要去重视的,如何在保证数据可靠传输的状况下进行高效的做业呢?

首先考虑最简单的状况,就是串行进行上面的一系列操做,一个分组操做完后才进行下一个分组的传输。这样的方式称之为停等协议。这种协议对于网络利用率实在太差了,咱们能够类比一下若是咱们在一个线程中进行一系列串行I/O的操做,这个咱们是不能接受的。

那么改为类比并发的方式处理确定是更为稳当的,咱们容许发送多个分组无需等待确认,这种技术称之为流水线,经过该技术对可靠传输协议会带来影响以下:

  1. 增长序号范围,天然你传递的分组多了,那么相对应的序号数量确定就上去了。
  2. 发送方和接收方须要由缓存多个分组。
  3. 所须要的序号范围以及对缓冲的要求取决于数据传输协议如何处理丢失,损坏以及延时过大的分组。

上面的影响TCP的开发人员提出了两种方式去解决:回退N步以及选择重传

回退N步协议(滑动窗口协议)

回退N步协议(GBN)也称之为滑动窗口协议,其做用是容许发送方发送多个分组并且无需等待确认,可是受限于流水线中未确认的分组的最大数不能超过N。下面的图中显示了发送方的序号范围:

能够看到在窗口长度范围内有已发送但未确认的数据,以及可用可是未发送的数据,在后面的数据(紫红色)只能等待窗口中的数据发送被确认后才有机会进入窗口中,至关于窗口主动进行了滑动,这也就是GBN称为滑动窗口协议的缘由。

GBN的运行过程以下描述:

  • 首先在发送方进行发送数据的时候,首先会检查滑动窗口中是否有数据,没有的话则加入滑动窗口,而且当即发送;若是窗口满了,则在缓冲区中进行等待调用。
  • 在接收方接收到数据的时候会验证该数据性的正确性,须要注意的是GBN协议要求数据是按序传递的,若是数据失序了,接收方会丢弃全部失序分组,也就是说,GBN能够保证序号为n的分组以前全部数据都是正确排序接收到的,这种方式称之为累计确认。当数据正确,则接收方返回一个ACK给发送方。
  • 若是发送方检测到了超时事件或者错误事件,那么发送方会重传全部已发送的还未被确认过的分组数据,这也是为何被称之为回退N步协议的缘由。

GBN好处在于容许发送方发送多个分组并且无需等待确认,可是也存在着很是明显的性能问题,单个分组一旦出了错就会自动重传全部已发送未确认的数据,所以又提出了选择重传协议。

选择重传协议

选择重传协议经过让发送发仅仅重传接收方出错的分组,避免没必要要的重传操做。这种个别的,按需的重传要求接收方逐个确认正确接收的分组,再次用窗口长度N来限制流水线中未完成,违背确认的分组数。接收方会接收失序的分组,直到全部丢失的分组被接收到为止,而后按序的交付于上层程序。

选择确认机制

选择确认机制能够认为是选择重传以及回退N步协议的综合体,即接收方有选择性的确认失序的报文段,而不是累计确认最后一个正确接收的有序报文段,只重传未被接收方确认过的报文段。更加详细的内容能够看这篇文章,写的很是浅显易懂。

这里总结一下可靠数据传输原理思路图:


TCP协议

首先整理一下该节中会遇到的缩写:

  • MSS:最大报文段长度
  • rwnd:接收窗口
  • cwnd:拥塞窗口
  • Seq:序号
  • ACK:确认号
  • ssthresh:慢启动阈值
  • SYN:同步序列编号(Synchronize Sequence Numbers),是TCP/IP创建链接时使用的握手信号。

TCP协议是基于可靠数据传输原理,这也是为何上面整理了:靠数据传输原理的相关内容。首先看下TCP报文段结构吧:

TCP的首部为20字节,主要的字段说明以下:

  • 32比特的序号字段(Seq)以及32比特的确认号(ACK)字段,用于发送方和接收方实现可靠数据传输服务。
  • 16比特接收窗口(rwind)字段,即图中的窗口大小,用于流量控制,标识接收方愿意接受的字节数量。
  • 6比特的标志字段,其中ACK确认数据的有效性,RST,SYN,FIN标识连接的简历和拆除(三次握手中能够见到)。

首先介绍一下序号字段,序号的概念创建在传送的字节流之上,一个报文段的序号为报文段首字节流的编号,假设一段字节流为1000字节,每一个报文段大小为200字节,那么第一个报文段序号为0,第二个为200,第三个为400,以此类推。

确认号的概念则是发送方但愿从接送方收到的下一节数据的序号,好比发送方已经从接收方收到了0-200字节的数据,此时发送方再发送一个报文段给接收方,而且带上确认号201,代表但愿收到201以及以后的全部字节。

接下来画个流程图来加深理解一下序号和确认号的概念吧,假设客户端和服务端的字节流的起始序号分别为20和40,而且报文段的字节大小都是1字节:

  • 首先客户端发送序号20,因为尚未数据从服务端接收,因此确认号为40,表示当前客户端的字节流序号为20,而且但愿从服务端接收到确认号40以及之后的数据。
  • 服务端接收到客户端传来的报文段,解析得到结果知道了客户端的需求,因此服务端发送的序号为40,而且发送确认号21表示21之前的数据已经收到了,但愿接收21以及之后的数据。
  • 客户端接收到了服务端传来的消息,知道了服务端的需求,发送了序号为21,以及确认号为41的报文段给服务端。

三次握手和四次挥手

TCP协议经过三次握手和四次挥手来保证链接的创建与拆除操做。首先看下三次握手:

  • 首先客户端的TCP向服务器发送一个特殊的TCP报文段,该报文段是不包含应用层数据的,在这个报文段首部中的SYN标志位会被设置为1,在上面报文段结构中能够看到对应的结构位置。另外,客户端会随机选择一个初始序号x放在报文段中的序号字段中。
  • 服务器收到客户端发过来的报文段,解析获取SYN字段值,而且为该TCP链接分配缓存和变量,而且向客户端发送容许链接的报文段。该报文段中也不包含应用层数据,主要包含三个信息:SYN字段设置为1,ACK设置为x+1,Seq设置本身的初始化序号y。
  • 客户端接收到服务端发送过来的响应报文段,也为该链接分配缓存以及变量,同时再发送一个报文段确认创建链接,这时候的报文段是能够携带应用层数据的,这是报文段中的相应字段:SYN设置为0,Seq=x+1,ACK=y+1。

经过三次握手,双方创建了链接,就能够相互发送/接收数据了。那么为何要三次握手呢?网络得来的答案以下:

为何A还要发送一次确认呢?能够二次握手吗?

主要为了防止已失效的链接请求报文段忽然又传送到了B,于是产生错误。如A发出链接请求,但因链接请求报文丢失而未收到确认,因而A再重传一次链接请求。后来收到了确认,创建了链接。数据传输完毕后,就释放了链接,A工发出了两个链接请求报文段,其中第一个丢失,第二个到达了B,可是第一个丢失的报文段只是在某些网络结点长时间滞留了,延误到链接释放之后的某个时间才到达B,此时B误认为A又发出一次新的链接请求,因而就向A发出确认报文段,赞成创建链接,不采用三次握手,只要B发出确认,就创建新的链接了,此时A不理睬B的确认且不发送数据,则B一致等待A发送数据,浪费资源。

四次挥手用于断开双方的链接,主要流程以下图所示:

该内容来自这位大牛的文章,我只是作搬运工,底下内容的ACK以及ack两个不是特别明白,看计算机网络自顶向下中没有解释,不过不影响理解

  • A的应用进程先向其TCP发出链接释放报文段(FIN=1,序号seq=u),并中止再发送数据,主动关闭TCP链接,进入FIN-WAIT-1(终止等待1)状态,等待B的确认。
  • B收到链接释放报文段后即发出确认报文段,(ACK=1,确认号ack=u+1,序号seq=v),B进入CLOSE-WAIT(关闭等待)状态,此时的TCP处于半关闭状态,A到B的链接释放。
  • A收到B的确认后,进入FIN-WAIT-2(终止等待2)状态,等待B发出的链接释放报文段。
  • B没有要向A发出的数据,B发出链接释放报文段(FIN=1,ACK=1,序号seq=w,确认号ack=u+1),B进入LAST-ACK(最后确认)状态,等待A的确认。
  • A收到B的链接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1),A进入TIME-WAIT(时间等待)状态。此时TCP未释放掉,须要通过时间等待计时器设置的时间2MSL后,A才进入CLOSED状态。

为何链接的时候是三次握手,关闭的时候倒是四次握手?

由于当Server端收到Client端的SYN链接请求报文后,能够直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。可是关闭链接时,当Server端收到FIN报文时,极可能并不会当即关闭SOCKET,因此只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端全部的报文都发送完了,我才能发送FIN报文,所以不能一块儿发送。故须要四步握手。

流量控制

一条TCP链接每一侧的主机都会为该链接创建一个接受缓存来保存数据,当TCP接收到正确的数据的时候就会放入到缓存当中,相关应用程序则会在合适的时间去缓存中读取数据。那么若是发送方发送数据过快致使了接受方的缓存溢出了就会形成问题。

解决该问题的方案就是流量控制,流量控制是一个速度匹配的服务,即便得发送方的发送速率和接收方应用程序的读取速率相匹配。TCP使发送方维护一个窗口的变量来提供流量控制,就是咱们在TCP报文段结构中的接收窗口字段,代表接收方还有多少可用的缓存空间。因为TCP为全双工通讯,因此接收方和发送方各有一个接收窗口。

下面简单看个例子:

  • 刚开始的窗口大小为5个报文段,首先发送方发送了5个报文段,而且第一个,第二个已经被确认,因此窗口前移两个报文段
  • 发送方继续发送数据,在受第四个报文段的确认后,发送服务端要求把接受窗口改为4个报文段,因此窗口被缩小了。

拥塞控制

拥塞控制主要用于解决网络拥塞的问题,网络拥塞缘由主要在于太多的源想要以太高的速率发送数据。TCP中实现的拥塞控制主要有以下方式:

  • 慢启动
  • 拥塞避免
  • 快速恢复和快速重传

发送方会维护一个拥塞窗口(cwnd)来控制发送速率

慢启动的原理以下:

当一条TCP链接开始的时候,cwnd的值通常设置为一个MSS,首先传递一个报文段,当接收到该报文段的确认时候,cwnd值就变成2个MSS,而后发送两个报文段,当这两个报文段被确认后,cwnd值就变成4个MSS而后发送4个报文段,以此类推

慢启动呈指数幂的形式增长拥塞窗口,可是也不能无限制的去增长对应的拥塞窗口,慢启动会伴随着一个变量共同使用:ssthresh(慢启动阈值)。当cwnd的值等于ssthresh的时候,就会进入拥塞避免的策略当中去。

当进入拥塞避免的时候,cwnd按线性规律增加。

一条TCP链接有时会因等待重传计时器的超时而空闲较长的时间,慢开始和拥塞避免没法很好的解决这类问题,所以提出了快速重传和快速恢复的拥塞控制方法。

快重算法机制是,丢包了,接收端重复发送丢包前的ACK,发送端每发送一个包过来,接收端就发相同的ACK回去,这个ACK是对丢包以前的确认。当接收端连续收到3个相同的ACK,它就知道发生丢包了,根据ACK序号就能重发丢的包。其并不是取消了重传机制,只是在某些状况下更早的重传丢失的报文段(若是当发送端接收到三个的确认ACK时,则判定分组丢失,当即重传丢失的报文段,而没必要等待重传计时器超时)。

快恢算法主要是跟着快重算法一块儿使用的,因为发送方如今认为网络极可能没有发生拥塞,所以如今不执行慢开始算法,而是把cwnd值设置为慢启动阈值减半后的值,而后开始执行拥塞避免算法,是拥塞窗口的线性增大。

因此拥塞控制的基本流程是以下:

  • 先慢启动,达到cwnd=ssthresh时,进入拥塞避免。
  • 若是发生丢包,进入拥塞发生。由于丢包有两种不一样处理办法,因此拥塞发生也有两种不一样的处理办法。
  1. 计算ssthresh,cwnd,从新进入慢启动,再等到cwnd=ssthresh时,再次进入拥塞避免。
  2. 计算ssthresh,cwnd,快速重传,再等到cwnd=ssthresh时,再次进入拥塞避免。(步骤2就称为快速恢复)

总结

TCP的可靠性应该是相对于UDP不可靠传输来讲的,由于UDP提供的是不可靠的数据报服务,不保证数据报能到达接收端,可能会有丢失;另外处于传输层之下的IP层也是不可靠的,仅提供尽力而为的端到端数据传输服务,不做任何保证。因此TCP的可靠性是指基于不可靠的IP层在传输层提供可靠的数据传输服务,主要是指传输数据不会损坏或丢失,并且全部数据都是按照发送顺序进行传送。实现TCP的可靠传输有如下机制:

  1. 校验和(校验数据是否损坏)
  2. 定时器(分组丢失则重传)
  3. 序号(用于检测丢失的分组和冗余的分组)
  4. 确认(接收方告知发送方正确接收分组以及指望的下一个分组)
  5. 否认确认(接收方通知发送方未被正确接收的分组)
  6. 窗口和流水线(用于增长信道的吞吐量)。

参考资料

https://blog.csdn.net/u014738387/article/details/52046502

https://blog.csdn.net/mxway/article/details/42784495

《计算机网络-自顶向下》

http://www.javashuo.com/article/p-ooymcqhd-mo.html

http://www.javashuo.com/article/p-xdjkkgbk-nc.html

http://www.javashuo.com/article/p-hvkgbelr-cs.html

相关文章
相关标签/搜索