多路复用与多路分解
网络层提供的是主机到主机之间的逻辑通信 传输层提供的是应用程序之间(进程之间)的逻辑通信 多路复用:收集不同socket的数据块,并为其封装上首部信息,传递给网络层 多路分解:从网络层拿到数据块,标识出套接字进而将其定向到该套接字并交付给传输层
UDP的套接字是由二元组标识的,即IP地址与端口号。当两个套接字具有相同的目的IP与目的端口号,那么他们将被定向到同一个socket。源端口号和源IP的作用是用来区分返回地址。而TCP的套接字是由四元组标识的
udp
udp的优点:
- 采用udp时,无需关注拥塞控制,可以毫无延迟的将报文段发送。有些实时应用有一个最小的发送速率限制,不希望过多的延迟报文段的发送,因此采取udp更合适
- udp无需建立连接,降低连接时延
- udp不必维护连接状态,可以支持更多活跃用户
- udp分组首部开销小
可靠数据传输原理
可靠数据传输协议(TCP)的下层协议是不可靠的(IP) 版本1:假设底层信道是完全可靠的 此时,接收方无需对发送方回复任何信息,发送方也无需等待接收方的确认信息,因为底层信道是完全可靠的,不必担心出现差错 版本2:假设底层信道会出现比特差错 此时,比特在底层信道传输过程中可能会出现差错。解决该问题的方案是 1.提供差错检验机制,比如奇偶校验和,海明码校验 2. 提供一种反馈机制,当接收方收到的数据经校验发生了错误的时候,需要发聩给发送端 3.发送端需要提供重传功能 版本2存在一个显著的问题,我们无法知道反馈机制的反馈结果的正确与否,即ACK与NAK是否会出现差错。这种情况下,我们提供的解决方案是:当提供了模糊不清的ACK或NAK分组时,我们对数据进行重传。但是,这又会引入一个新的问题:我们无法知道传来的数据是一次重传,还是一个全新的数据包。因此,我们这里引入一个新的机制:序列号。以此来区分数据是重传的还是新数据 版本3:假设底层不仅会出现比特差错,还会丢包 应对这种方式,我们应该引入一个新的机制:定时器。 当发送一个数据包时,我们启动定时器。当定时器时间结束依旧没有收到返回结果时,说明数据很有可能丢失,因此我们应重传该数据。当定时器结束之前收到响应数据时,我们应终止定时器。
总结 可靠数据传输主要依靠检验和,序号,定时器,肯定和否定确认等机制
流水线式可靠数据传输协议
上述的可靠数据传输协议的功能毋庸置疑。但是,由于他是一个停等协议,这就造成了它的性能实际上是很低的。解决这个问题的方案是,不以停等方式运行,在收到确认前,我们可以一次性发送多个数据包。 这对我们上述协议提出了新的要求。 首先,我们应增大序列号的范围。因为每个输送中的分组必须有一个唯一的序列号。 其次 ,协议的发送方与接收方需要缓存多个分组。发送方应缓存已发送但未被确认的分组。接收方应缓存已经被正确接收的分组 最后,我们应提供一种新的处理丢失或损坏分组的方式,这种方式为选择重传和回退N步
回退N步
发送方 1.发送方缓存一个N大小的窗口。当已发送但未确认的数据包数量大于N时,便不再允许数据进入这个窗口。当窗口未满时,我们发送数据并将这个数据加入窗口。 2.当收到一个序列号位m的确认时,说明m之前的所有数据都已经被接收方收到 3.当超时未响应时,发送方重传所有已发送但未响应的数据
接收方 1.当接收方接收到一个按序的分组时,将该分组接收并响应该分组的ack,当接收方接收到一个无序分组时,将其丢弃并响应之前接到的分组的ack
选择重传
接收方也定义一个窗口缓存,缓存那些失序的但已被接收的分组。等之前的分组被传过来之后再一起传递给上层。
tcp
在完整的了解了可靠数据的传输原理之后,我们就可以进行tcp的学习了。 客户通过套接字传输数据,数据一旦通过套接字,就会被放入发送缓存中。发送缓存时三次握手期间设置的缓存,接下里tcp会不断的从中取出数据,包装上首部并传输给网络层。而取出数据的长度受制于MSS,即最大报文段长度。MSS又受制于MTU,即最大链路层帧长度。MSS+首部字段应该小于MTU。
tcp报文段比udp多出了 1.32比特的序列号字段和32比特的确认号字段(用于可靠数据传输) 2.16比特的接收窗口字段(用于流量控制) 3.4比特的首部长度字段(首部长度是可变的) 4.可变长的选项字段(用于协商MSS以及作为窗口调节因子) 5.6比特的标志字段(包括ACK,NAK,FIN等)
序列号和确认号 tcp传输的数据是建立在字节流之上。因此一个报文段的编号是该报文段首字节的字节流编号。举例来说,假如数据流为一个500000字节大小的文件,MSS被设置为1000,数据流的首字节序号被设置为0,则TCP将构建出500个报文段,给第一个报文段设置序列号为0,第二个报文段设置序列号为1000,第三个报文段设置序列号为2000,以此类推。这就是序列号。而每次传输的初始序列号一般是随机设置的,这是为了降低先前连接传输的旧报文段被误认为是当前连接传输的有效报文段的概率。 确认号就是期望收到的下一字节的序号。举例来说,主机A向主机B发送数据,假设先前主机A已经收到了0-535编号的所有字节,因此主机A会将确认号设置为536。确认号可以被捎带在数据报文段 tcp的可靠数据传输实现 1.超时时间加倍。当达到超时时间后,重传最小序号的还未被确认的报文段,并将下一个超时时间设置为原来的两倍。(实际上是一种不完全的拥塞控制) 2.快速重传。当连续收到三个冗余ACK时,立刻重传最小序号的还未被确认的报文段 3.选择确认。会将正确接收的失序的报文段缓存起来,等之前的到达后一起传递给上层。 tcp的流量控制 由于tcp的接收方存在缓存,而接收方应用可能忙于其他事务导致很长时间不去读取缓存中的数据,因此缓存可能会溢出。而tcp通过报文段中的接收窗口字段来告知发送方该连接的缓存还有多少可用空间 tcp的三次握手与四次分手 三次握手: 第一次,客户端发送一个特殊的的tcp报文段,这个报文段不带任何应用层数据,但在报文段的首部中的SYN比特被设置为1。另外,客户端会随机选择一个初始序号,将其放入报文段的序列号字段中。 第二次,服务端提取出客户端发送的报文段,并为该tcp连接分配缓存和变量,并向客户端发送允许连接的报文段。这个报文段的SYN被置为1,确认号为客户端随机选择的确认号+1,序列号为服务端随机选择。这个报文段被称为SYN_ACK报文段 第三次,客户端收到SYN_ACK报文段后,客户端为服务端分配缓存和变量,并发送一个报文段,由于此时连接已经建立,SYN被设置为0,确认号被设置为服务端随机选择的+1;
四次分手: 第一次,客户端发送一个特殊的报文段,该报文段首部的FIN被设置为1 第二次,服务端发送确认报文段 第三次,服务端发送自己的终止报文段 第四次,客户端对服务端的终止报文段进行确认 tcp的拥塞控制
拥塞控制有三个重点: 1.发送方如何限制它向其连接发送流量的速率呢? 2.发送方如何感知从它到目的地之间的路径上存在拥塞呢? 3.当发送方感知到端到端的拥塞时,采用何种算法来改变其发送速率呢?
第一点,其实很简单。发送方会跟踪一个额外的变量:拥塞窗口。他和接收窗口一起来限制数据的发送速率 第二点,当出现超时或者三个冗余ACK时,就说明网络很有可能出现拥塞 第三点,就是著名的TCP拥塞控制算法:慢启动,拥塞避免,快速恢复
慢启动 cwnd(拥塞窗口)的值首先被设置为1个MSS,每收到一次确认,就会增加一个MSS,1、2、4、8。因此,TCP发送速率起始慢,但在慢启动阶段以指数增长。何时结束这种指数增长呢?当首次出现丢包后,会将慢启动阈值设置为当前cwnd,并重新开始慢启动过程(cwnd重新设置为1个MSS)。而当慢启动的cwnd的值大于慢启动阈值时,继续指数增长可能会有些鲁莽,因此应进入拥塞避免状态 拥塞避免 一旦进入拥塞避免,cwnd的值是上次遇到拥塞时的一半。此时采取了一种较为保守的方法,每个RTT只将cwnd的值增加一个MSS。举例来说,若在一个RTT内发送了10个报文段,则每个到达的ACK增加1/10个MSS。这种称为线性增长。何时应停止这种线性增长呢?当出现超时事件时,与慢启动一样,阈值被设置为cwnd值的一半,cwnd被设置为1个MSS。随后进入慢启动阶段。而当出现3个冗余ACK事件时,我们反应不应该像超时那样剧烈(虽然二者都是丢包指示事件),我们将 阈值被设置为cwnd值的一半后,只将cwnd的值减半,接下来进入快速恢复状态 快速恢复 对收到的每个冗余ACK,cwnd增加一个MSS。最终,当丢失报文段的最后一个冗余ACK到达时,TCP在降低cwnd后进入拥塞避免状态。如果在这期间出现超时事件,快速恢复在执行和慢启动同样的动作后,进入慢启动状态。
|