使用checksum进行差错检测,类似于udp的差错检测方式,使用回卷加法,之后将加和进行反码运算,放在数据的最开头,并且回卷加法使用8比特加法。
在发送方的检测使用时,差错和使用0,接收方接收到的数据进行整体的差错检测(包括差错和和数据报文),如果没有差错,那么接收方的回卷加法和将是0。
差错和存放的数据为回卷加法的反码。
同样的,对于ACK/NAK包也需要进行差错检测。
其中数据表文表示如下。
标志位为1字节(8比特);序号位1字节(8比特)表示数据包的序号,并且ACK/NAK也会包含标志位和序号位;之后的数据全部为信息数据。
对于整个发送的整条信息的最后一个段来说,如果是最后一个报文段,我们需要一个字节来表示他的数据段长度:
如图所示,长度位位一个字节(8比特),表示后面的数据包的长度,因此如果最后一个数据包长度为509字节时,整个报文的长度可能达到513字节,因此再接受的时候需要统一按照513字节接收。
建立连接的时候使用3次握手,并且和TCP有些许不同。
第一次的客户端向服务器发送握手协议标志位最低位为1(一个字节内的最低位为从右到左第一位),标志位其他的位为0,并且没有序号位和数据位,之后计算差错和,发送给服务器;
服务器接收到后返回一个数据包,标志位倒数第二位的1,其他位为0,没有序号位和数据,之后计算差错和,返回给客户端;
客户端收到这个数据包之后发送一个标志位倒数第三位为1,其他位为0的数据包,表示连接建立完成,此时两台机器可以开始进行可靠数据传输。
链接建立阶段发送得3个数据包长度均为2字节(为差错检测位和标志位)。
对于一个数据包的长度是有限制的,对于不是整个传输数据结尾的数据包来说最多数据长度为509个字节,即数据报文为512个字节(加上标志位和序号位)。对于传输段最后的不完整的数据来说则有多少发多少。
对于非结尾数据包,标志位的倒数第4位为1;对于结尾数据包,标志位的倒数4,5位为1;
因为一整个链接期间,可能发送得整个数据段不止一个,因此序号位需要在整个链接未断开时不断递增,否则接收方可能会混淆不同的阶段的数据。
服务器接收到数据包之后,对于数据进行差错检测,对于"差错和"和"数据报文"进行统一的校验操作,ACK和NAK数据包长度均为3字节(包含差错检测位,标志位和序号位,序号位为其对应的接收包的序号,NAK序号可能不准确)。
因为停等机制的存在,我们需要在设置适当的停止等待协议,在数据包丢包的时候就会进行超时重传;并且在ACK/NAK进行丢包的时候也能进行数据包的超时重传。
为了和之前保持一致,重传数据包的的标志位也和之前的标志位相同。
断开连接使用两次挥手协议,首先断开数据包由客户端发送。
客户端需要接收到服务端的连接之后才能完全关闭连接,否则进行重传,链接断开的两个数据包长度均为2字节(包含差错检测位和标志位)。
如果在挥手和握手期间传递的数据包出错,则从头进行整个挥手握手过程,保证连接信息完整性。
程序使用了两份代码进行实现,一份为客户端代码,为发送方,一份为服务端代码,为接收方。
程序会让发送方输入服务器的ip地址和所要发送的文件的文件名,之后程序进行连接和处理。
首先我们会将文件名作为一个单独的数据段发送过去,之后发送整个文件的数据段,在接收端接收到两端数据之后,就可以根据文件名进行数据解析工作,或者在本地存储数据。
在文件传输过程中的超时的设置:
因为在服务端recvfrom是进行阻塞接受的,我们先使用库函数将其阻塞时间进行设置,在我们的TIMEOUT范围之内。
传输的关键位置的丢包问题:
握手挥手过程中的丢包因为无法确认和检测,只能进行重新进行握手挥手实现,并且在挥手中进行超时次数的设置,超过次数认为对方完全断网,自己则进行资源回收后断网。
传输第一个数据段的最后一个包的重传,可能会让接收方误认为是第二段的结束,我们需要设置全程传输时的序号递增,这样就可以解决上述问题
对于上层应用程序发送来的数据段,首先进行各个发送包的封装,开始流水线的式的进行数据的发送,在发送窗口未填满时,边发送边进行接收检测,查看对方的是否有累计确认状态码发送过来。对于一个累计确认状态的序号高于当前的base序号的包,则进行发送窗口的滑动,并且更新定时器,继续数据包发送。
使用类似3-1的回卷加法,进行差错检测位置的设定
由于使用累计确认策略,我们将不会在接收方进行NAK包的设定。只有当当前序号之前的所有包都接收到了,发送这个序号对应的ack包,否则即使接受到了之后的包,也只会发送之前连续接受到的正确的包的ACK。
对于一个包内的编码设置依然如3-1报告中所示。
对于发送方我们维护一个大小为WINDOW_SIZE的序号窗口,这部分数据为已经发送确还未确认的。如果窗口未满,则我们可以继续发送数据包;如果窗口满了,则需要等待ACK确认后窗口的减小,之后才能发送数据包。
对于一个数据段的结束,因为窗口此时不能继续扩大,因此我们需要做特殊的标记处理,此时只许缩小窗口等待全部数据包确认,则可以退出发送函数。
对于每一个发送得数据包,我们记录了他发送出去的时间点,存储在一个队列里timer_list中,之后根据当前clock()判断队首的包是否发送超时,超时后进行回退重发,并且清空队列;如果未超时收到包,则需要弹出队列队首,即更新计时器。
为了方便测试与运行,我们的的窗口大小,文件名和接收方ip均可以输入确定,之后在发送过程中我们会输出发送的进度,方便观察。
对于整体的GBN协议设计,我们使用了while循环来回调换recv和send进行实现,避免了使用线程导致的繁琐。
因为我们传送的序列号只有一个Char大小(8比特),因此肯定存在序号回卷的可能,使得ACK序号和发送方窗口是否已满的判断很难通过base和nextpacknum判断,因此我们可以利用前面提到的timer_list的长度和变换进行判断,使得序列号回卷变得可以处理。
在对方ACK包丢失的情况下,我们需要处理队列的出队个数,我们通过in_list维护在队列中的序号这样可以O(1)进行查找,之后就可以应对ACK丢包现象对于发送方的影响。
整体数据段设计和3-1相同,为了观察方便,在本次实验中将其整个数据段长度设置为250字节
本次实验依然使用累计确认,并且对于ack的设置和对于其余的设置和对于累计方式和3-2相同,之后使用滑动窗口对发送方数据包进行处理。
对于拥塞窗口我们使用了两个状态进行拥塞控制
状态一:慢启动状态,发送窗口初始设置为1,然后每次进行进行增加,即收到对方一个合格的ack之后,发送方会连续发送两个数据段过去。这样就可以模拟慢启动状态的指数增长,即每次发送窗口会增加一倍。
状态二:拥塞避免状态,发送窗口初始为转移到这个状态时的样子,然后窗口的增长方式变为没个发送阶段增长1个MSS,即下一个完整的发送窗口将会比当前完整的发送窗口大1,进行线性增长,直到出现以下状况:
状态三:快速恢复状态,在产生3个冗余ack之后,就会进入这个状态,这个状态主要用于快速重传丢失的ack包,一直重传当前的丢失包,
我们最开始以慢启动状态启动,之后按照遇到的情况在3个状态之间切换,完成整个数据包的发送和接受任务
只需要最开始输入接受方的ip地址,之后程序可以自动完成拥塞控制和累计确认滑动窗口等工作
运行环境均为使用router传送1M数据使用的时间,时间越短越好,计时单位为秒,mss为510,窗口大小为25,timeout为500ms
配置 | 停等协议 | 滑动窗口 |
---|---|---|
丢包率 0% | 1.235s | 0.234s |
丢包率 5% | 97.246s | 87.35s |
丢包率 10% | 158.312s | 150.11s |
分析:当传输的丢包率增加时,各个协议因为需要停等超时触发的超时重传十分耽误时间,因此传输用时普遍增加。
因为滑动窗口可以更高效利用发送的带宽,提高带宽利用率,因为相较于停等协议有部分提升,但是由于丢包问题,GBN协议要求的回退N完全的重传也导致时间延长很大,因此较停等协议更优但是差别不大。
运行环境均为使用router传送1M数据使用的时间,时间越短越好,计时单位为秒,丢包率5%,mss为250,timeout为1500ms
窗口大小 | 传输时间 |
---|---|
5 | 469.96s |
25 | 470.33s |
50 | 619.30s |
运行环境均为使用router传送1M数据使用的时间,时间越短越好,计时单位为秒,丢包率0%,mss为250,timeout为1500ms
窗口大小 | 传输时间 |
---|---|
5 | 2.53s |
25 | 2.52s |
100 | 2.29s |
分析:滑动窗口协议因为其每次发送都会发送窗口大小的数据段,因此在丢包率较小的时候,越大的窗口总的来说是越优的,因为丢包率较小,传输时间差异不大,但是总体来说还是可以看出其更优。
当丢包率较大是,因为窗口的大小增加会导致GBN的时候重传的数据包过多,因此窗口太大会导致时间过长。
因此我们需要根据丢包率队窗口大小做一个折中。
运行环境均为使用router传送1M数据使用的时间,时间越短越好,计时单位为秒,mss为250,timeout为1500ms,无拥塞控制协议窗口大小为25
丢包率 | 有拥塞控制 | 无拥塞控制 |
---|---|---|
0% | 2.29s | 2.53s |
5% | 391.76s | 469.96s |
10% | 662.25s | 1257.86s |
分析:拥塞控制就是一个在丢包率和窗口大小上的一个动态调整,因为其可以在没有丢包时尽量的扩大自己窗口提高带宽利用率;在丢包率提高是,减小窗口,防止GBN重传过多,因此,其在大部分情况下优于无拥塞控制的方案。
|
| 5% | 391.76s | 469.96s |
| 10% | 662.25s | 1257.86s |
[外链图片转存中…(img-xEOtdbCD-1663153543811)]
分析:拥塞控制就是一个在丢包率和窗口大小上的一个动态调整,因为其可以在没有丢包时尽量的扩大自己窗口提高带宽利用率;在丢包率提高是,减小窗口,防止GBN重传过多,因此,其在大部分情况下优于无拥塞控制的方案。