• TCP/IP协议--TCP的交互数据流和成块数据流


      前边讲了TCP连接的建立和终止,分别要三次握手和四次通信。这些报文段都只包含首部,没有数据部分。    这里就讲讲数据传送的一些细节。一个TCP连接建立成功以后,就可以开始传送数据了~

    一般TCP数据传输中,按分组数量算的话,一半是成块数据(比如FTP应用),一半是交互数据(比如Telnet应用)。
    如果按照字节数比较的话,成块报文段远远高于交互报文段(显然交互报文段都是几个字节的数据...)

    TCP的交互数据流:

    比如Rlogin应用,每一次按键(每个字节)都会发送包,而不是敲一行命令回车后发送,并且Rlogin需要远程系统(服务器)回显我们(客户)键入的字符。这样一个字节就产生4个报文段。如图:


    一般可以将服务器返回的报文段2和3进行合并—按键确认与按键回显一起发送。这种合并的技术 (称为经受时延的确认)。

    就是说这个确认段的发送要稍微等一会,看看自己有没有还要发送的数据,放在一块传过去~这样就稍微提高了效率,减少网络负载。

    Nagle算法:
    前边演示在一个Rlogin连接上客户一般每次发送一个字节到服务器,这就产生了一些41字节长的分组:20字节的IP首部、20字节的TCP首部和1个字节的数据。在局域网上, 这些小分组(被称为微小分组(tiny gram))通常不会引起麻烦,因为局域网一般不会出现拥塞。但在广域网上,这些小分组则会增加拥塞出现的可能。一种简单和好的方法就是采用Nagle算法。

    该算法要求一个TCP连接上最多只能有一个未被确认的未完成的小分组,在该分组的确认到达之前不能发送其他的小分组。而是,在TCP的发送缓冲区去收集这些少量的分组,并在确认到来时以一个分组(注意是组装成了一个分组)的方式发出去。

    这表示,如果确认到达的快,那么发送的就快。如果在局域网中使用到了Nagle算法,可以想象数据得输入的多快才能造成为了等待确认到来,而塞很多数据。。所以一般都是在广域网TCP传输才用到Nagle算法。

    -- 关闭Nagle算法:
    可以看出来,Nagle算法是为了减少网络负载,只有一个ack到达了,我才接着发送过去数据。这就表明会有延迟,而这种延迟对交互数据的应用来说也有些蛋疼。。所以有时候也要禁用Nagle算法。

    TCP的成块数据流:

    TCP使用的被称为滑动窗口协议的流量控制方法。该协议允许发送方在停止并等待确认前可以连续发送多个分组(注意区分前边的Nagle算法,等待ack的时候是组装成了一个分组发过去。这里的滑动窗口协议是一口气发送多个分组~)。由于发送方不必每发一个分组就停下来等待确认,因此该协议可以加速数据的传输。
    如图时间序列:

    说明下:这里的实现是接收方每收到两个报文段,就会发送一个ACK(比如ack7是对于4和5的报文段。为什么ack8只返回了报文段6的确认?因为经受时延的定时器溢出了...表示我也想等你的比如报文段9过来,再发送ack8,但是定时器到点儿了,我必须发送了哈哈~)。

    值得注意的是滑动窗口协议并不要求对每一个接收的数据段都要确认。

    下图是针对这个时间序列图的滑动窗口协议示意图:

    这里说下滑动窗口协议:

    1-11是模拟的11个字节,1-3个字节已经被发送并且确认(可以看出滑动窗口就不包含已经确认的字节了,向右做滑动)。接收方通告的窗口称为提供的窗口(offered window),它覆盖了从第4字节到第9字节的区域,4-6字节是已经发送出去了但还没有得到确认,此时滑动窗口不能右移(因为有可能4-6的确认段我收不到,如果右移,我就没法重发,找不到了哈哈),且通告窗口(接收端提供的窗口大小)大小为6。发送方计算它的可用窗口,该窗口表明多少数据可以立即被发送(通告窗口减去发送但没确认的大小)。

    当接收方确认数据后,这个滑动窗口不时地向右移动。窗口两个边沿的相对运动增加或减少了窗口的大小。我们使用三个术语来描述窗口左右边沿的运动:

    如图:

    1) 称窗口左边沿向右边沿靠近为窗口合拢。这种现象发生在数据被发送和确认时。

    2) 当窗口右边沿向右移动时将允许发送更多的数据,我们称之为窗口张开。这种现象发生在另一端的接收进程读取已经确认的数据并释放了TCP的接收缓存时。

    3) 当右边沿向左移动时,我们称之为窗口收缩。 协议中强烈不建议这种方式(通常不会发生)。

    4) 左边沿往左边移动(这个不可能了,因为左边沿是根据ack确认段确定的,表示左边沿左边的数据已经得到了确认,如果说发生,也是ack重复了。。)

      -窗口大小:

    这里说下接收端的通告窗口大小。窗口大小表示,我最大可以容纳多少数据。来个图说明下:

    1-3个报文段是在建立TCP连接。在第二个ack段中,接收端告诉发送端,我的通告窗口大小是6144个字节。发送端比较实惠,我也不见外,直接给你发过去6个数据段(每个1024,6个就是6144)。重点看一下第10个报文段,这是接收端把这过来的6个段都确认了,通告窗口大小由原来的6144变成了2048,这个很可能是因为我的接收缓冲区里仍然有数据(6144-2048个字节)没有被应用程序调取走。

       -慢启动:

        前边的TCP连接,可以看到,当连接建立后,发送端总是一下发送好几个分组过去,直至达到接收方的通告窗口大小为止。
    当然这种策略在局域网中,几乎没有什么问题。但是如果发送方和接收方之间是一个存在着多个路由器和速率较慢的链路时,这就可能出现拥塞的问题...
    TCP需要支持一种慢启动的算法。顾名思义,是一点点加速,而不是一次传太多过去。
    实现原理:发送方需要支持一个窗口,拥塞窗口(congestion window,cwnd)。当TCP连接建立好以后,拥塞窗口被初始化为1个报文段,发送端每收到ACK,就在cwnd中增加报文段(比如说这个ACK是确认的一个报文段,那么我就增加一个报文段;下次我就发俩报文段,收到这俩的ACK后,我就增加到4个报文段长度。有点类似于成倍增加,这就是慢启动)。那么现在有两个窗口了,发送端传数据的时候是用拥塞窗口大小还是接收端的通告窗口大小呢?这里是取两者中较小的一个大小。

  • 相关阅读:
    oracle中rownum和rowid的区别
    Delphi 流
    Delphi 关键字
    Android控件系列之ImageView
    Android控件系列(未完待续)
    Android控件系列之CheckBox
    Android控件系列之ProgressBar&在Android中利用Handler处理多线程
    Android控件系列之Button以及Android监听器
    Android控件系列之Toast
    Android控件系列之TextView
  • 原文地址:https://www.cnblogs.com/firstForEver/p/5387863.html
Copyright © 2020-2023  润新知