目录
TCP与UDP的区别
TCP协议和UDP协议为什么会共存
TCP和UDP分别对应的协议
为什么 TCP 叫数据流模式? UDP 叫数据报模式?
怎样使用 UDP 实现 TCP 的可靠传输
TCP通过哪些措施,保证传输可靠?
TCP的拥塞控制原理
TCP的滑动窗口协议与停止等待协议的区别
TCP流量控制原理
TCP(Transmission Control Protocol)的概念 TCP是一种面向连接的,提供可靠交付服务和全双工通信的,基于字节流的端到端的传输层通信协议。
TCP在传输数据之前必须先建立连接,数据传输结束后要释放连接。 每一条TCP连接只能有2个端点,故TCP不提供广播或多播服务。 TCP提供可靠交付,通过TCP连接传输的数据,无差错、不丢失、不重复、并且按序到达。 TCP是面向字节流的。虽然应用进程和TCP的交互是一次一个数据块(大小不等),但TCP把应用程序交下来的数据看成仅仅是一连串的无结构的字节流。TCP并不知道所传输的字节流的含义。
UDP(UserDatagram Protocol)的概念 UDP是一种无连接的,尽最大努力交付的,基于报文的端到端的传输层通信协议。 UDP在发送数据之前不需要建立连接 UDP不保证可靠交付,主机不需要建立复杂的连接状态 UDP是面向报文的。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界,即应用层交给UDP多长的报文,UDP就照样发送,即一次发送一个报文。在接收端,UDP一次交付一个完整的报文。 UDP没有拥塞控制,网络出现的拥塞不会使源主机的发送速率降低。 UDP支持一对一、一对多、多对一和多对多的交互通信。 UDP的首部开销小,只有8个字节,比TCP的20个字节的首部要短。
使用情况 TCP协议适用于对效率要求相对低,但对准确性要求相对高的场景下,或者是有一种连接概念的场景下;而UDP协议适用于对效率要求相对高,对准确性要求相对低的场景。
很多文章都说TCP协议可靠,UDP协议不可靠!为什么前者可靠,后者不可靠呢?既然UDP协议不可靠,为什么还要使用它呢?所谓的TCP协议是面向连接的协议,面向连接是什么呢?TCP和UDP都是传输层的协议!从编程的角度看,就是两个模块(模块就是代码的集合,一系列代码的组合提供相应的功能!模块化最终目的就是:分工协作!模块化好处:便于扩展开发以及维护!)。
在一个TCP连接中,仅有两方进行彼此通信,因此广播和多播不能用于TCP TCP使用校验和,累积确认和重传机制来保证可靠传输 TCP使用滑动窗口机制来实现流量控制,通过动态改变窗口的大小进行拥塞控制
|
1)大家要知道,一种物理线路,单位时间内,能够创建的“虚拟信道”是有限的! 2)使用TCP协议传输数据,当数据从A端传到B端后,B端会发送一个确认包(ACK包)给A端,告知A端数据我已收到!UDP协议就没有这种确认机制!这就是为什么说TCP协议可靠,UDP协议不可靠. QQ普通会员就是使用的UDP协议进行传输数据!既然UDP协议自身没有确认机制,这个工作可以交给应用层的进程来完成(QQ)!大家使用QQ的时候,感觉出错的几率还是非常小吧!当然,把这个确认工作完全交给QQ自身来做,就直接导致了,QQ软件体积增大! 有些应用,对数据传输可靠性要求非常高,例如大家浏览网页,通过网页注册帐号、转帐等服务,这是不容许出错的,使用TCP协议能把出错的可能性降到最低(当然,网络自身很糟糕,TCP协议也没办法)。但是,提供这种可靠服务,会加大网络带宽的开销,因为“虚拟信道”是持续存在的,同时网络中还会出现大量的ACK和FIN包! 因此,鱼和熊掌不可兼得,需根据实际情况选择传输协议。TCP协议提供了可靠的数据传输,但是其拥塞控制、数据校验、重传机制的网络开销很大,不适合实时通信,所以选择开销很小的UDP协议来传输数据。 |
TCP对应的协议: (1) FTP:定义了文件传输协议,使用21端口。 (2) Telnet:一种用于远程登陆的端口,使用23端口,用户可以以自己的身份远程连接到计算机上,可提供基于DOS模式下的通信服务。 (3) SMTP:邮件传送协议,用于发送邮件。服务器开放的是25号端口。 (4) POP3:它是和SMTP对应,POP3用于接收邮件。POP3协议所用的是110端口。 (5) HTTP:是从Web服务器传输超文本到本地浏览器的传送协议,使用80端口。
UDP对应的协议: (1) DNS:用于域名解析服务,将域名地址转换为IP地址。DNS用的是53号端口。 (2) SNMP:简单网络管理协议,使用161号端口,是用来管理网络设备的。由于网络设备很多,无连接的服务就体现出其优势。 (3) TFTP(Trival File Transfer Protocal),简单文件传输协议,该协议在熟知端口69上使用UDP服务。
|
所谓的“流模式”,是指TCP发送端发送几次数据和接收端接收几次数据是没有必然联系的,比如你通过 TCP连接给另一端发送数据,你只调用了一次 write,发送了100个字节,但是对方可以分10次收完,每次10个字节;你也可以调用10次write,每次10个字节,但是对方可以一次就收完。
原因:这是因为TCP是面向连接的,一个 socket 中收到的数据都是由同一台主机发出,且有序地到达,所以每次读取多少数据都可以。
所谓的“数据报模式”,是指UDP发送端调用了几次 write,接收端必须用相同次数的 read 读完。UDP是基于报文的,在接收的时候,每次最多只能读取一个报文,报文和报文是不会合并的,如果缓冲区小于报文长度,则多出的部分会被丢弃。
原因:这是因为UDP是无连接的,只要知道接收端的 IP 和端口,任何主机都可以向接收端发送数据。 这时候,如果一次能读取超过一个报文的数据, 则会乱套。 |
要使用 UDP 来构建可靠的面向连接的数据传输,就要实现类似于 TCP 协议的超时重传,有序接收,应答确认,校验,滑动窗口,流量控制等机制,等于说要在传输层的上一层(或者直接在应用层)实现 TCP 协议的可靠数据传输机制,比如使用 UDP 数据包+序列号,UDP 数据包+时间戳等方法,在服务器端进行应答确认机制,这样就会保证不可靠的 UDP 协议进行可靠的数据传输 |
TCP提供一种面向连接的、可靠的字节流服务。 面向连接:意味着两个使用TCP的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个TCP连接。在一个TCP连接中,仅有两方进行彼此通信。广播和多播不能用于TCP。
TCP通过下列方式来提供可靠性: 1、应用数据被分割成TCP认为最适合发送的数据块。这和UDP完全不同,应用程序产生的数据报长度将保持不变。(将数据截断为合理的长度,数据块)
2、当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。 (超时重传)
3、当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒 (对于收到的请求,给出确认响应) (之所以推迟,可能是要对包做完整校验)
4、TCP将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段。 (校验出包有错,丢弃报文段,不给出响应,TCP发送数据端,超时会重发数据)(校验机制)
5、既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。如果必要,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。 (对失序数据进行重新排序,然后才交给应用层)
6、既然IP数据报会发生重复,TCP的接收端必须丢弃重复的数据。(对于重复数据,能够丢弃重复数据)
7、TCP还能提供流量控制。TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。(TCP可以进行流量控制,防止较快主机致使较慢主机的缓冲区溢出)TCP使用的流量控制协议是可变大小的滑动窗口协议。
字节流服务: 两个应用程序通过TCP连接交换8bit字节构成的字节流。TCP不在字节流中插入记录标识符。我们将这称为字节流服务(bytestreamservice)。
TCP对字节流的内容不作任何解释。TCP不知道传输的数据字节流是二进制数据,还是ASCII字符、EBCDIC字符或者其他类型数据。对字节流的解释由TCP连接双方的应用层解释。 |
为防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。拥塞控制所要做的都有一个前提:网络能够承受现有的网络负荷。拥塞控制是一个全局性的过程,涉及到所有的主机、路由器,以及与降低网络传输性能有关的所有因素。 拥塞控制代价:需要获得网络内部流量分布的信息。在实施拥塞控制之前,还需要在结点之间交换信息和各种命令,以便选择控制的策略和实施控制。这样就产生了额外的开销。拥塞控制还需要将一些资源分配给各个用户单独使用,使得网络资源不能更好地实现共享。
几种拥塞控制方法: 慢开始(slow-start )、拥塞避免(congestion avoidance ); 快重传( fastretransmit )、快恢复( fastrecovery )。 一切的基础还是慢开始,这种方法的思路是这样的: 1. 发送方维持一个叫做“拥塞窗口”的变量,该变量和接收窗口共同决定了发送者的发送窗口,发送方的发送窗口的上限值应当为接收方窗口rwnd和拥塞窗口cwnd这两个变量中的较小的一个; 2. 当主机开始发送数据时,避免一下子将大量字节注入到网络,造成或者增加拥塞,选择发送一个1字节的试探报文; 3. 当收到第一个字节的数据的确认后,就发送2个字节的报文; 4. 若再次收到2个字节的确认,则发送4个字节,依次递增2的指数级; 5. 最后会达到一个提前预设的“慢开始门限ssthresh”,比如24,即一次发送了24个分组,此时遵循下面的条件判定: a. cwnd < ssthresh, 继续使用慢开始算法; b. cwnd > ssthresh,停止使用慢开始算法,改用拥塞避免算法; c. cwnd = ssthresh,既可以使用慢开始算法,也可以使用拥塞避免算法; 6. 所谓拥塞避免算法就是:每经过一个往返时间RTT就把发送方的拥塞窗口+1,即让拥塞窗口缓慢地增大,按照线性规律增长; 7. 当出现网络拥塞,比如丢包时,将慢开始门限ssthresh设置为出现拥塞时的发送方窗口的一半(但不能小于2),然后将cwnd设为1,执行慢开始算法(较低的起点,指数级增长);
上述方法的目的是在拥塞发生时循序减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够的时间把队列中积压的分组处理完毕。慢开始和拥塞控制算法常常作为一个整体使用,而快重传和快恢复则是为了减少因为拥塞导致的数据包丢失带来的重传时间,从而避免传递无用的数据到网络。下图为TCP Tahoe(慢开始+拥塞避免)版本,实际已废弃不用
快重传的机制是: 1. 接收方建立这样的机制,如果一个包丢失,则对后续的包继续发送针对该包的重传请求; 2. 一旦发送方接收到三个一样的确认,就知道该包之后出现了错误,立刻重传该包; 3. 此时发送方开始执行“快恢复”算法: a. 慢开始门限变为出现拥塞时的一半(为了预防网络发生拥塞); b. 拥塞窗口cwnd设为上面变化后的慢开始门限的值; c. 执行拥塞避免算法(高起点,线性增长);
新的TCP Reno版本是在快重传后采用快恢复算法而不是采用慢开始算法。 在采用快恢复算法时,慢开始算法只是在TCP连接建立时和网络出现超时 时才使用。
|
滑动窗口协议中,允许发送方发送多个分组(当有多个分组可用时)而不需等待确认,但它受限于在流水线中为未确认的分组数不能超过某个最大允许数N。滑动窗口协议是TCP使用的一种流量控制方法,此协议能够加速数据的传输。只有在接收窗口向前滑动时(与此同时也发送了确认),发送窗口才有可能向前滑动。 收发两端的窗口按照以上规律不断地向前滑动,因此这种协议称为滑动窗口协议。 当发送窗口和接收窗口的大小都等于1时,就是停止等待协议。
所谓滑动窗口协议,自己理解有两点: 1.“窗口”对应的是一段可以被发送者发送的字节序列,其连续的范围称之为“窗口”; 2.“滑动”则是指这段“允许发送的范围”是可以随着发送的过程而变化的,方式就是按顺序“滑动”。在引入一个例子来说这个协议之前,我觉得很有必要先了解以下前提: a. TCP协议的两端分别为发送者A和接收者B,由于是全双工协议,因此A和B应该分别维护着一个独立的发送缓冲区和接收缓冲区,由于对等性(A发B收和B发A收),我们以A发送B接收的情况作为例子; b. 发送窗口是发送缓存中的一部分,是可以被TCP协议发送的那部分,其实应用层需要发送的所有数据都被放进了发送者的发送缓冲区; c. 发送窗口中相关的有四个概念:已发送并收到确认的数据(不在发送窗口和发送缓冲区之内)、已发送但未收到确认的数据(位于发送窗口之中)、允许发送但尚未发送的数据以及发送窗口外发送缓冲区内暂时不允许发送的数据; d. 每次成功发送数据之后,发送窗口就会在发送缓冲区中按顺序移动,将新的数据包含到窗口中准备发送;
TCP建立连接的初始,B会告诉A自己的接收窗口rwnd大小,比如为‘20’: 字节31-50为发送窗口
A发送11个字节后,发送窗口位置不变,B接收到了乱序的数据分组,如下图:
只有当A成功发送了数据,即发送的数据得到了B的确认之后,才会移动滑动窗口离开已发送的数据;同时B则确认连续的数据分组,对于乱序的分组则先接收下来,避免网络重复传递:
|
1.概述 所谓的流量控制就是让发送方的发送速率不要太快,让接收方来得及接收。利用滑动窗口机制可以很方便的在TCP连接上实现对发送方的流量控制。TCP的窗口单位是字节,不是报文段,发送方的发送窗口不能超过接收方给出的接收窗口的数值。接收方在返回的ACK中会包含自己的接收窗口的大小,以控制发送方的数据发送。
如上图所示A向B发送数据。在连接建立时,B告诉A接收窗口rwnd(receiver window)= 400,单位字节,因此发送方A的发送窗口不能400。 (可以看出,B向A发送的三个报文段都设置了 ACK = 1以保证字段有效,后面的rwnd值就是接收方对发送方的三次流量控制。) 如图所示,说明了利用可变窗口大小进行流量控制。设主机A向主机B发送数据。双方确定的窗口值是400.再设每一个报文段为100字节长,序号的初始值为seq=1,图中的箭头上面大写ACK,表示首部中的确认字段为ACK,小写ack表示确认字段的值。 接收方的主机B进行了三次流量控制。第一次把窗口设置为rwnd=300,第二次减小到rwnd=100最后减到rwnd=0,即不允许发送方再发送过数据了。这种使发送方暂停发送的状态将持续到主机B重新发出一个新的窗口值为止。 假如,B向A发送了零窗口的报文段后不久,B的接收缓存又有了一些存储空间。于是B向A发送了rwind=400的报文段,然而这个报文段在传送中丢失了。A一直等待收不到B发送的非零窗口的通知,而B也一直等待A发送的数据。这样就死锁了。为了解决这种死锁状态,TCP为每个连接设有一个持续计时器。只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器,周期性的发送一个零窗口探测报文段。对方就在确认这个报文的时候给出 现在的窗口大小(注意:TCP规定,即使设置为零窗口,也必须接收以下几种报文段:零窗口探测报文段、确认报文段和携带紧急数据的报文段)。
2.TCP报文段发送时机的选择 TCP报文段发送时机主要有以下几种选择途径。 1)TCP维持一个变量,它等于最大报文段长度MSS,只要缓存中存放的数据达到MSS字节就组装成一个TCP报文段发送出去。 2)由发送方的应用程序指明要求发送报文段,即TCP支持的推送操作 3)是发送方的一个计时器期限到了,这时就把当前已有的缓存数据装入报文段发送出去。
传递效率的问题: 一个显而易见的问题是:单个发送字节单个确认,和窗口有一个空余即通知发送方发送一个字节,无疑增加了网络中的许多不必要的报文(请想想为了一个字节数据而添加的40字节头部吧!),所以我们的原则是尽可能一次多发送几个字节,或者窗口空余较多的时候通知发送方一次发送多个字节。 对于前者我们广泛使用Nagle算法,即: 1. 若发送应用进程要把发送的数据逐个字节地送到TCP的发送缓存,则发送方就把第一个数据字节先发送出去,把后面的字节先缓存起来;(拥塞控制) 2. 当发送方收到第一个字节的确认后(也得到了网络情况和对方的接收窗口大小),再把缓冲区的剩余字节组成合适大小的报文发送出去; 3. 当到达的数据已达到发送窗口大小的一半或已达到报文段的最大长度时,就立即发送一个报文段; 对于后者我们往往的做法是让接收方等待一段时间,或者接收方获得足够的空间容纳一个报文段或者等到接收缓存有一半空闲的时候,再通知发送方发送数据。 |