计算机网络学习(二)——传输层

1.多路复用与多路分解

当我们使用网络时,每一时刻会接受各种数据。比方说你用浏览器打开了网页,还在聊QQ,还在下载东西。那么我打开网页所传输的数据是怎么交付给浏览器的而不是QQ呢?
即我从网络受到的元数据是如何交付给对应的进程的呢?
接触过网络编程的人知道网络应用的数据传输和接受都是经过套接字Socket完成的,发送端套接字要标注上发送的端口(从哪个端口发送)以及目的端口(接收方的端口),而接收端的套接字只负责监听某一个网络端口,当有数据到达时由接收端套接字负责接收。
套接字的数据又是谁交付的呢?这就是我们所说的多路复用和多路分解了。当我们的运输层收到数据,运输层负责将数据交付给对应套接字的过程叫做“ 多路分解”(很好理解,一堆掺杂在一起的数据把它们分开)。而当我们由套接字发送数据时,运输层做的就是把这些数据进行封装然后交给网络层,这一过程叫做“ 多路复用”。

2.无连接传输:UDP

UDP很像我们寄信。只要你知道对方的地址和邮编你就可以写一封信然后向对方寄出,你们可能并不认识(至少对方可能不认识你,比方说你给偶像寄的什么骚扰信件啥的),但是对方会收到。在UDP里地址就变成了ip地址和端口号,只要对方在监听某个端口你就可以向这个端口发送UDP报文。当然和寄信一样你的数据可能由于某种原因不会被受到,这既是所谓 无连接。(可以对比我们打电话,这就是有连接的。你讲话对方拿起听筒肯定能听到)
UDP比寄信多了一点就是差错检测功能,当然这个功能设计的比较简单。因此 如果检测到差错那么肯定出现了数据错误,可是没有检测到也不一定不会出现数据错误(但是UDP认为是正确的)。UDP功能比较简单,发现了出错的报文要么就丢弃,要么继续交付但是会告诉你这个报文的数据出现了错误。

3.可靠数据传输原理

光有不可靠的数据传输不能满足我们的需求,因此我们需要一个可靠的数据传输方式。即 保证数据能够无差错的被接受

模型一:rdt1.0

我们假设我们的底层信道是可靠的(即在交付给传输层时数据能够按照正确的顺序到达而且无差错)。这样的话运输层唯一要做的就是将接收的数据原封不动(也不全是,要拆封一下)的交给上层的套接字,将从套接字接收的数据打包后交付给下层。

模型二:rdt2.0

当然肯定不会这么简单,我们现在假设底层信道接收的数据可能有数据错误但是仍然按照正确的顺序进行交付。这样除了上面的基本功能外,我们的传输层作为接收方还需要有差错检测和反馈功能(告诉发送方你的数据有问题),而作为发送方也不能像原来那样一股脑全发过去,必须要等到接收方的正确反馈ACK(我收到数据了,数据没问题)才继续发送下一个,要是收到了错误的反馈NAK(你的数据在路上颠坏了),那么重新传输刚才传输的数据报。
看起来似乎解决了问题,可是我们忽略了重要的一点:万一接收方的反馈数据ACK或者NAK损坏了怎么办?我们的做法(事实上有其他的思考方式,详见书上P140页)是如果收到的ACK或者NAK受损,那么发送方就认为接收方没有收到正确的数据于是 重新发送。可是重新发送带来了新的问题:万一我已经收到了但是你又给我发送了同样的数据包那不就重复了吗,而且会导致我的接受顺序错误。解决这个问题就很简单了:我发送方只给发送的数据报编号就行了,这样接收方就知道这个分组是不是冗余分组了。

模型三:rdt3.0

现在到了最现实的阶段了,即我们在底层传输时不仅有可能发送数据损坏,还可能发生丢包(不但会颠坏,还有可能在中途掉了)。我们必须在前面建立的传输方式上增添对丢包的处理。
如何检测丢包呢?我们的方式是如果在传输后过了一段时间没有收到接收方的ACK,那发送方就认为接收方没有收到刚才发送的数据报,于是重传该分组。那么问题来了:如果我收到了刚才的分组可是我的ACK信号由于路上塞车没及时到达怎么办呢?对于接收方而言我们在前面的传输方式已经有了对于冗余分组的处理方式,可是发送方却接收了一个数据报带来的两个ACK,因此我们的ACK也需要加上序号来告诉发送方第几个分组被正确的接收了。

流水线可靠数据传输协议

rdt3.0有一个很致命的问题就是它是停等协议。如果有一个数据报没有收到接收方的ACK信号,那么发送方将不会发送下一个数据报。这样一来的话效率会十分的底下。如何解决呢?很简单,我们可以允许发送方发送多个分组无需等待确认,这种技术被称为流水线。当然,流水线需要发送方和接收方缓存多个分组(发送方缓存发送但未确认的分组,接收方缓存需要正确接收的分组,即序号打乱的分组)。下面介绍流水线对于丢失、损坏和延时过大分组的处理:
回退N步(GBN)
规定:流水线中未确认的分组数不能超过N,对于序号n的分组进行确认当且仅当第n个分组和它之前的分组都被正确接收(发送方和接收方都是)。因此该协议也被成为滑动窗口协议。
对接收方而言,如果收到失序的分组将把它丢弃。

选择重传(SR)
GBN是丢弃那些失序的分组然后重新传输,而SR是将失序的分组缓存起来(也发送ACK信号)直到丢失分组(比该分组序号小的分组)都被收到为止。这样的话发送方仅仅需要重新传输那些丢失和受损的数据报即可。
SR的问题:当我们面对有限序号范围时(发送序号为0~n 0~n依次重复),如果窗口过大会让接收方不清楚传输的分组是冗余分组还是新的分组。例如,发送窗口为0 1 2 3 0 1 2 ,窗口长度为3。假设0 1 2已被接收,这是窗口滑动到3 0 1,即接收方下面期待接收的数据报序号为3 0 1。不幸的是接收方的ACK信号未能成功到达发送方,这时发送方将重新传输0 1 2 。问题就是当接收方收到这三个数据报后对于序号为0和1的分组会认为这时新的分组,可是实际上它是冗余分组。这也是SR接收方和发送方信息不同步带来的问题。
怎么解决呢?我们只要控制窗口大小是它不会出现这种冗余分组和新分组序号相同即可,因此最大窗口长度为[n/2]。

4.面向连接的传输:TCP

铺垫了这么多,下面介绍这个重要的协议TCP。

连接的建立

了解了刚才可靠数据传输的协议,我们来猜一猜TCP是如何建立连接的。既然连接是双向的则必须要求:A、B之间有A->B和B->A的数据通路且双方都知道这一点。
要建立连接则必须一方先发送请求,这里我们假设A向B发送一个建立连接的数据报(SYN报文段),B收到后说明:B知道A->B的数据通路已经建立  可是这时A什么都不知道
因此B必须向A发送一个应答信息,如果A收到则说明:A知道了B->A和A->B的数据通路已经建立(收到B的应答消息就说明了B刚才接受到了A发送来的数据报)可是B并不知道B->A的数据通路是否建立
所以最后A再向B发送一个数据报(可以承载有效信息),B收到后则说明刚才发送给A的数据A收到了,因此B也知道了B->A的数据通路已经建立。
事实上TCP连接的建立就是这样的,这也被称为 三次握手

数据的发送

数据从套接字到达传输层后进入到发送缓存中等待被发送。TCP在一个数据报中封装的应用层数据量是有大小限制的,称为最大报文段长度(MSS)。之后TCP为每块数据添加一个TCP首部(通常为40个字节)就封装成了TCP报文段。

TCP报文段结构

根据我们前面的讨论,如果让我们来设计报文段,哪些东西是必须的。 数据段当然是必须的,我们主要考虑发送方添加的首部字段。
1.首先和UDP一样,由于是发送方加上的报文段,那必须要说明信息从哪里来要到哪里去,即 源端口号(发送方)和 目的端口号(接收方)。
2.既然是可靠传输,必须要有检测数据是否正确的 检验和字段,这点和UDP一样。
3.根据我们可靠数据传输的讨论, 序号也是必须的。关于序号的划分我们多说一点。这个序号并不是我们之前想象的那样是1 2 3 4 这种在发送队列中排队的序号,而是字节流中的序号。比方说第一个数据报的在字节流中是从0~999字节,那么它的序号就是0,下一个数据报是从1000~1999那它的序号就是1000,即报文中首字节的字节流编号。
对于 确认号,接收方等待哪一个字节就确认号就是哪个。继续上面的例子,接收方收到了0~999的数据报,下一个期待接收的字节编号是1000,那么确认号就是1000。如果接收完第一个后直接接收了第三个(2000~2999)数据报,那么第三个数据报的确认号仍然是1000,这样发送方也知道第二个数据报未收到。这称为累计确认。(需要说明的是,假设发送方的第一个待确认序号为sendbase而收到的ACK序号为y,正常情况下收到的y和sendbase相等。如果有某个ACK丢失出现y>sendbase则说明接收方已经正确接收所有y之前的字节,这时将sendbase更新为y。即便有某个ACK丢失,发送方仍然能够正确的确认被接收的数据)

流量控制

这里我们讨论TCP发送方和接收方的缓存是如何运作的,称为流量控制。我们的原则是数据不能从缓存当中溢出。
发送方维护一个 接受窗口用来告诉发送方接收方还有多少缓存空间(记做rwnd)。并且跟踪两个变量lastbytesent(最后一个已发送字节)和lastbyteacked(最后一个已接受字节),两者的差即为发送方发送却未被接收的字节。这些字节可能在接收方的缓存中也可能在传输的路上,因此lastbytesent-lastbyteacked≤缓存中的数据量≤rwnd。这样才保证了数据不会溢出。

拥塞控制

发送方记录一个变量cwnd称为 拥塞窗口,它表示发送方发送的最大速率为cwnd/RTT。即发送cwnd的数据量能够使数据在一个RTT内正常接收。
下面介绍拥塞控制算法,主要包含3个部分:
1.慢启动。
当TCP连接开始时,cwnd的值设置为一个较小的值,如果没有发生拥塞,则让cwnd的值翻倍。如果出现由超时出现的丢包时间(拥塞),TCP将cwnd值设置为1然后重新开始慢启动。同时将慢启动阈值ssthresh设置为cwnd/2,以后当cwnd的值等于ssthresh是进入 拥塞避免模式。如果检测到三个冗余ACK进行 快速重传

2.拥塞避免。

进入拥塞避免状态表面距离拥塞已经不远了,这时应该缓慢的增大cwnd的值,我们选择每次增加一个MSS(可以理解为一个数据报)。一旦出现拥塞,将cwnd设置成1,阈值ssthresh设置为cwnd的一半(和慢启动相同)。如果是三个冗余ACK(不是超时出现的丢包),将cwnd和阈值设置为原来cwnd的一半。

3.快速恢复
每收到一个冗余ACK,cwnd增加1个mss,当丢失报文段的ACK到达后,TCP进入拥塞避免状态。如果超时则进入慢启动状态。
基于STM32F407,使用DFS算法实现最短迷宫路径检索,分为三种模式:1.DEBUG模式,2. 训练模式,3. 主程序模式 ,DEBUG模式主要分析bug,测量必要数据,训练模式用于DFS算法训练最短路径,并将最短路径以链表形式存储Flash, 主程序模式从Flash中….zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值