libjingle源码解析(4)-【PseudoTcp】建立UDP之上的TCP(2):对交互数据流的处理

对交互数据流的处理

TCP包含两类数据流,交互数据流和成块数据流。交互数据流的特点是每个报文数据字节数比较小,大部分是10字节一下,而成块数据流的特点是大部分报文是满长度的,一般能达到MSS。

本文先介绍一些TCP和PTCP对交互数据流的处理。

交互式输入

    Rlogin是典型的交互数据流应用,每一按键都会产生数据分组,使客户端传输一个报文,接连总共产生4个报文:

    a.C传输交互按键数据

    b.S确认C的数据

    c.S回显C的按键

    d.C确认S的回显

    上面的报文b,c可能会同时包含在一个报文段。而对于TCP报文-有40个字节的头部的协议报文来说每次只传输一个字节是个极大的浪费,此外Rlogin这类应用会在短时间内按N个字符,按如上的方式,至少要传输3*N个报文。

经受时延的确认

    经受时延的确认考虑了时间有关的细微之处,对于交互类应用,短时间内会产生多个报文。对于TCP,当接收数据时,并不立即发送确认,而先缓存,延迟发送,以便在短时间如果有该方向的数据需要发送,则一同发送,这样能减少ACK报文的个数,提高报文的利用率。TCP通常等待200ms后发送ACK。

    对于PTCP来说,也支持延时确认,默认延时时长为100ms,可以通过选项OPT_ACKDELAY更改延时时间。不另外,如果出现连续两个不含数据的ACK需要发送,则不会等到100ms,直接会发送ACK报文。PTCP发送ACK的时机如下:

    A. 和SEND数据一起发送

    B. 等到超时(100ms后没有数据时)时发送

    C. 出错时发送(如发现对方传来的数据和预期的不一致,或者ACK被丢失)

    虽然PTCP是等到100ms后发送ACK,但没有提供任何定时器,只提供了下次需要被提醒的时间(通过方法GetNextClock),然后由业务层来实现定时器并通知到时(通过方法NotifyClock)。这样,业务层就会有灵活的方式设置定时器,比如通过消息循环,等待事件,完成端口等等。

Nagle算法

    Nagle算法是为了避免在广域网上出现大量的TCP小分组报文段。该算法要求一个TCP连接上最多只有一个未被确认的小分组。当已经发送的一个分组没有被确认前,该算法积累所有需要发送的数据,等到未被确认的分组确认了,一同发送,这样在短时间内出现的小分组合并成一个报文发送,提高了报文的利用率。这个算法是自适应的,得到确认越快,则发送频率越高。伪代码如下:

    if there is new data to send

      if the window size >= MSS and available data is >= MSS

        send complete MSS segment now

      else

        if there is unconfirmed data still in the pipe

          enqueue data in the buffer until an acknowledge is received

        else

          send data immediately

        end if

      end if

    end if

    PTCP也支持Nagle算法,可以通过选项OPT_NODELAY开启或者关闭。Nagle算法的实现比较简单,当尝试发送数据时,发现如果有未确认的数据且等待发送的数据长度小于MSS,则延迟发送,如下:

    

[cpp] view plaincopy

  1. void PseudoTcp::attemptSend(SendFlags sflags) {  
  2.     ......  
  3.         // Nagle's algorithm.  
  4.         // If there is data already in-flight, and we haven't a full segment of  
  5.         // data ready to send then hold off until we get more to send, or the  
  6.         // in-flight data is acknowledged.  
  7.         if (m_use_nagling && (m_snd_nxt > m_snd_una) && (nAvailable < m_mss))  {  
  8.           return;  
  9.         }  
  10.     ......  
  11.     }  

窗口大小通告

    TCP和PTCP都通过头部的window字段通告接收缓冲区的可用窗口大小。当客户端收到服务器的数据,并有等待发送的数据时(开启Nagle算法时会经常出现此情况),通告给服务器的窗口大小总是小于接收缓冲区的大小,是因为,应用层还没有拿取刚从服务获取的数据之前,就会尝试发送被缓冲的数据。

    PTCP的实现如下:

    当PTCP接收对方发送的数据时会调用NofifyPacket->parse->process,在Process先调用attemptSend发送缓冲的数据,然后通知应用层有可读数据。

[cpp] view plaincopy

  1. bool PseudoTcp::process(Segment& seg) {  
  2. ......  
  3.         attemptSend(sflags);  
  4.          // If we have new data, notify the user  
  5.          if (bNewData && m_bReadEnable) {  
  6.               m_bReadEnable = false;  
  7.               if (m_notify) {  
  8.                 m_notify->OnTcpReadable(this);  
  9.               }  
  10.               //notify(evRead);  
  11.            }  
  12.          return true;  
  13. }  
时间: 2024-10-24 13:23:30

libjingle源码解析(4)-【PseudoTcp】建立UDP之上的TCP(2):对交互数据流的处理的相关文章

libjingle源码解析(3)-【PseudoTcp】建立UDP之上的TCP(1):连接和关闭

PseudoTcp - 建立UDP之上的TCP(1):连接和关闭 mail:lihe21327 [at] gmail [dot] com 最近阅读了Libjingle的PseudoTcp.LibJingle很是下功夫做P2P了,在UDP之上做了可靠的传输协议PseudoTcp. 了解PseudoTcp之前,我们需要了解一些TCP的特性. 根据<TCP/IP详解>卷1,可以总结如下: 1.TCP是面相连接的,他需要3次握手和4次终止过程. 2.TCP支持Nangle算法和经受时延的确认来控制报文

libjingle源码解析(5)-【PseudoTcp】建立UDP之上的TCP(3):对成块数据流的处理

PseudoTcp对成块数据流的处理 上一篇谈论了TCP和PTCP对交互数据流的处理方法.这一篇谈论另一个数据流--成块数据流.成块数据流主要采用滑动窗口协议和慢启动算法来控制成块数据的流量. 滑动窗口     滑动窗口允许发送方在停止并等待确认前可以连续发送多个分组.因此发送方不必每发一个就停下来等待,这样可以加速数据的传输.这个Nagle算法冲突么?不会,因为成块数据流的分组都是满载传输的,根据Nagle算法,当等待发送数据的大小和窗口大小都大于MSS时,会立即发送.     如果发送方一直

libjingle源码解析(6)-【PseudoTcp】建立UDP之上的TCP(4):超时与重传

超时与重传       TCP是面向连接的可靠的运输层.当数据丢失时,TCP需要重传包.TCP通过设置定时器解决这种问题.     对每个连接,TCP有4个不同的定时器:         1)重传定时器:用于当希望收到另一端的确认,而没有收到时.         2)坚持定时器:使窗口大小信息保持不断流动.         3)保活定时器:可检测空闲连接另一端何时崩溃或重启.         4)2MSL定时器:测量TIME_WAIT状态的时间.       PTCP本身是没有提供定时器的,而通

Java集合学习(十二) TreeMap详细介绍(源码解析)和使用示例

这一章,我们对TreeMap进行学习. 第1部分 TreeMap介绍 TreeMap 简介 TreeMap 是一个有序的key-value集合,它是通过红黑树实现的. TreeMap继承于AbstractMap,所以它是一个Map,即一个key-value集合. TreeMap 实现了NavigableMap接口,意味着它支持一系列的导航方法.比如返回有序的key集合. TreeMap 实现了Cloneable接口,意味着它能被克隆. TreeMap 实现了java.io.Serializabl

Java集合学习(十一) Hashtable详细介绍(源码解析)和使用示例

这一章,我们对Hashtable进行学习. 我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable. 第1部分 Hashtable介绍 Hashtable 简介 和HashMap一样,Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射. Hashtable 继承于Dictionary,实现了Map.Cloneable.java.io.Serializable接口. Hashtable 的函数都是同步的,这意味着它是线

Java集合学习(十) HashMap详细介绍(源码解析)和使用示例

这一章,我们对HashMap进行学习. 我们先对HashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashMap. 第1部分 HashMap介绍 HashMap简介 HashMap 是一个散列表,它存储的内容是键值对(key-value)映射. HashMap 继承于AbstractMap,实现了Map.Cloneable.java.io.Serializable接口. HashMap 的实现不是同步的,这意味着它不是线程安全的.它的key.value都可以为null.此外

Java 集合系列10之 HashMap详细介绍(源码解析)和使用示例

概要 这一章,我们对HashMap进行学习.我们先对HashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashMap.内容包括:第1部分 HashMap介绍第2部分 HashMap数据结构第3部分 HashMap源码解析(基于JDK1.6.0_45)    第3.1部分 HashMap的"拉链法"相关内容    第3.2部分 HashMap的构造函数    第3.3部分 HashMap的主要对外接口    第3.4部分 HashMap实现的Cloneable接口 

Java 集合系列11之 Hashtable详细介绍(源码解析)和使用示例

概要 前一章,我们学习了HashMap.这一章,我们对Hashtable进行学习.我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable.第1部分 Hashtable介绍第2部分 Hashtable数据结构第3部分 Hashtable源码解析(基于JDK1.6.0_45)第4部分 Hashtable遍历方式第5部分 Hashtable示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3310887.h

Java 集合系列12之 TreeMap详细介绍(源码解析)和使用示例

概要 这一章,我们对TreeMap进行学习.我们先对TreeMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用TreeMap.内容包括:第1部分 TreeMap介绍第2部分 TreeMap数据结构第3部分 TreeMap源码解析(基于JDK1.6.0_45)第4部分 TreeMap遍历方式第5部分 TreeMap示例 转载请注明出处:http://www.cnblogs.com/skywang12345/admin/EditPosts.aspx?postid=3310928   第