实验三 编程实现可靠数据传输原理Go-Back-N

Go-Back-N 的有限状态机模型表示如图所示:

实验设置:

编程语言:python3

实验设置:

  1. 设置发送方和接收方
  2. 双方建立连接握手后,发送方向接收方发送多条数据

本实验中:

messages = '123,456,654,788,87364,875,8374'  # 可传输多条信息,每条信息以逗号隔开,每条信息分别依次发送

  1. 发送方向接收方传输数据时,按一定概率发生丢包,本实验设置丢包概率20%。(lost_probability = 0.2
  2. 设置接收方向发送方发送的回应不会丢失
  3. 对滑窗的第一个窗口,也就是最早发送的且没有ack的数据包设置时钟,计时到之后会重滑窗的所有数据包。
  4. 接收方采用累计确认方法

 实验文件结构:

 实验步骤:

Sender.py 关键代码:

发送消息:

# 尝试发送消息  
if(nextseqnum < base + window_size):  # 是否可以发送这个消息  
    # 发送消息  
    chksum_s = Mychecksum(str(nextseqnum) + message_list[nextseqnum-1])  
    sndpkt = str(nextseqnum) + ',' + message_list[nextseqnum-1] + ',' + chksum_s  # 打包数据nextseqnum,message,chksum  
    print('发送消息:', sndpkt)  
    conn.send(sndpkt.encode())  
    if base == nextseqnum:  # 发送的消息是滑窗的第一个窗口,开启计时  
        stop_timer = 0  
        pickle.dump(0, open('flag', 'wb'))  
        timer1 = threading.Thread(target=mytimer)  
        timer1.start()  
        print("开始计时")  
    message_flag[nextseqnum-1] = 1  # 发送过的消息相应的flag置为1  
    nextseqnum = nextseqnum + 1  
    time.sleep(1)   

接收响应:

# 接收消息
try:
    receive = conn.recv(1024).decode()
    if receive == 'Lost':  # 发生丢包,接收端没有收到消息,但发送端并不知道,因此不做任何动作
        has_receive = False
    else:
        has_receive = True
except:
    pass
if has_receive:  # 接收到接收端的回应
    print('接收消息:', receive)
    acknum, expectseqnum, chksum_r = receive.split(',')
    chksum_y = Mychecksum(acknum + expectseqnum)
    if chksum_r == chksum_y:  # 通过校验和校验
        base = int(acknum) + 1
        if base == nextseqnum:  # 滑窗第一个窗口接收到ack,计时停止
            stop_timer = 1
            print('结束计时')
        else:  # 代表接收端之前发送的的某个回应消息丢失了,但是由于是累计确认,仅需要开启新计时即可
            stop_timer = 0
            pickle.dump(0, open('flag', 'wb'))
            timer1 = threading.Thread(target=mytimer)
            timer1.start()
    time.sleep(1)

时钟:

# 检查定时器
time.sleep(1)
flag = pickle.load(open('flag', 'rb'))
print('检查定时器flag:', flag)
if(flag == 1):  # timeout 重新发送窗口中的所有包
    print('重新发送')
    nextseqnum = base
    for i in range(window_size):
        if base+i-1 < message_num:
            message_flag[base+i-1] = 0
time.sleep(1)
print()

Receiver.py 关键代码:

while True:
   f = random.random()  # 产生(0,1)之间的随机数
   
   # 模拟丢包
   if(f < lost_probability):
      rcvpkt = s.recv(1024).decode()
      seqnum, message, chksum_r = rcvpkt.split(',')
      if message == 'Message over':  # 是否传输完毕
         print(message)
         print('messages:', *message_list)
         print('Close')  # 传输完毕,关闭连接
         s.close()
         break
      print("Lost\n")
      s.send('Lost'.encode())  # 实际上丢包时,接收端并不会产生任何回应,此处仅为模拟丢包
      time.sleep(1)
   
   # 未丢包
   else:
      rcvpkt = s.recv(1024).decode()
      print('接收到的消息:', rcvpkt)
      seqnum, message, chksum_r = rcvpkt.split(',')
      chksum_y = Mychecksum(seqnum + message)
      if chksum_r == chksum_y:  # 校验和检验
         if int(seqnum) == expectseqnum:  # 检验收到的消息是否为期望的消息
      
            if message == 'Message over':  # 是否传输完毕
               print(message)
               print('\nmessages:', *message_list)
               print('Close')  # 传输完毕,关闭连接
               s.close()
               break
            
            expectseqnum = expectseqnum + 1
            ack = str(seqnum)
            print(f'ACK{ack}:{message}')  # 打印此次接收到的消息序号和消息内容
            message_list.append(message)  # 将此次消息放入消息组的列表中
            chksum_s = Mychecksum(ack + str(expectseqnum))  # 计算校验和
            sndpkt = ack + ',' + str(expectseqnum) + ',' + chksum_s  # 发送响应消息:已收到的消息序号,期望的下一消息序号,校验和
            print('发送消息:', sndpkt)
            s.send(sndpkt.encode())
         else:  # 收到的消息不是期望的消息
            s.send('Lost'.encode())
            print('Not expected seq')
      time.sleep(1)
      print()

实验结果:

发送端:

Hi Sender_Alice. Welcome to Chat Room
Initialising....
DESKTOP-BK14LMU ( IP )
Waiting for incoming connections...
Received connection from  IP ( 端口号 )
Receiver_Bob has connected to the chat room

发送消息: 1,123,0x9c9b  # 发送第1条消息
开始计时
接收消息: 1,2,0xcecd  # ack1
结束计时
检查定时器flag: 0

发送消息: 2,456,0x9895  # 发送第2条消息
开始计时
检查定时器flag: 0

发送消息: 3,654,0x9795  # 发送第3条消息
检查定时器flag: 0

发送消息: 4,788,0x9390  # 发送第4条消息
检查定时器flag: 1  # 在规定时间内,没有收到第2条消息的ack
重新发送

发送消息: 2,456,0x9895  # 重新发送的第2条消息
开始计时  # 重新计时
接收消息: 2,3,0xcdcc  # ack2
结束计时
检查定时器flag: 0

发送消息: 3,654,0x9795  # 重新发送的第3条消息
开始计时
检查定时器flag: 0

发送消息: 4,788,0x9390  # 重新发送的第4条消息
检查定时器flag: 0

发送消息: 5,87364,0x5d60  # 发送第五条消息
检查定时器flag: 1  # 在规定时间内,没有收到第3条消息的ack
重新发送

发送消息: 3,654,0x9795  # 重新发送第3条消息
开始计时
接收消息: 3,4,0xcccb  # ack3
结束计时
检查定时器flag: 0

发送消息: 4,788,0x9390  # 重新发送第4条消息
开始计时
接收消息: 4,5,0xcbca  # ack4
结束计时
检查定时器flag: 0

发送消息: 5,87364,0x5d60  # 重新发送的第5条消息
开始计时
检查定时器flag: 0

发送消息: 6,875,0x9292  # 发送第6条消息
检查定时器flag: 0

发送消息: 7,8374,0x9249  # 发送第7条消息
检查定时器flag: 1  # 在规定时间内,没有收到第5条消息的ack
重新发送

发送消息: 5,87364,0x5d60  # 重新发送的第5条消息
开始计时
接收消息: 5,6,0xcac9  # ack5
结束计时
检查定时器flag: 0

发送消息: 6,875,0x9292  # 重新发送的第6条消息
开始计时
接收消息: 6,7,0xc9c8  # ack6
结束计时
检查定时器flag: 0

发送消息: 7,8374,0x9249  # 重新发送的第7条消息
开始计时
接收消息: 7,8,0xc8c7  # ack7
结束计时
检查定时器flag: 0

Message over  # 消息已经全部发送成功,并接收方已全部接收
发送消息: 8,Message over,0xe97c
Close

接收端:

Hi Receiver_Bob. Welcome to Chat Room
Initialising....
Trying to connect to  IP ( 端口号 )
Connected...
Sender_Alice has joined the chat room

接收到的消息: 1,123,0x9c9b
ACK1:123
发送消息: 1,2,0xcecd

Lost  # 2号包丢失

接收到的消息: 3,654,0x9795
Not expected seq

接收到的消息: 4,788,0x9390
Not expected seq

接收到的消息: 2,456,0x9895  # 发送端重传了包2、3、4
ACK2:456
发送消息: 2,3,0xcdcc

Lost  # 3号包丢失

接收到的消息: 4,788,0x9390
Not expected seq

Lost  # 5号包丢失

接收到的消息: 3,654,0x9795  # 发送端重传了包3、4、5
ACK3:654
发送消息: 3,4,0xcccb

接收到的消息: 4,788,0x9390
ACK4:788
发送消息: 4,5,0xcbca

Lost  # 5号包丢失

接收到的消息: 6,875,0x9292
Not expected seq

Lost  # 7号包丢失

接收到的消息: 5,87364,0x5d60  # 发送端重传了包5、6、7
ACK5:87364
发送消息: 5,6,0xcac9

接收到的消息: 6,875,0x9292
ACK6:875
发送消息: 6,7,0xc9c8

接收到的消息: 7,8374,0x9249
ACK7:8374
发送消息: 7,8,0xc8c7

Message over
messages: 123 456 654 788 87364 875 8374
Close

完整代码见:https://download.csdn.net/download/llluuhp/87772153

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐