GBN-Python

实验内容:采用UDP Socket编程接口作为模拟物理层接口实现帧的发送和接收,协议采用双工方式进行数据通信。假设Host1和Host2分别向对方发送大文件,Host1先发送一帧到Host2,通过数据链路层的帧每次完成数据块的可靠传输,采用GBN协议,差错编码采用CRC-CCITT标准。

程序结构:分别调用Server.py开启进程1(Host1)和进程2(Host2),Host1和Host2可选择接收,发送或者关闭。接收则会调用Receiver.py创建接收线程,发送则会调用sender.py创建发送线程。Receiver和sender都通过UDT.py实现帧的发送。Timer.py实现计时器,实现超时重传。Packet.py实现组帧和提取帧中数据的功能。PDU.py定义帧格式。crc16.py是引入的库,实现计算crc和校验功能。

#sender.py

import socket
import PDU
import UDT
import _thread
import timer
import sys
import packet
import crc16
import time
import threading
interval=1


ack_expected=0      #累计确认,只用维护一个
num_packets=0
send_timer=timer.timer(interval)
log_filename=""
mutex = _thread.allocate_lock()
UDTER=UDT.UDT(0.0001,0.0001)
def send(sock,filename,IP_PORT,RECEIVER_ADDR):
    global UDTER
    global mutex
    global ack_expected
    global num_packets
    global send_timer
    global log_filename
    #Create log file
    log_filename=IP_PORT[0]+"_"+str(IP_PORT[1])+"_"+"log_file.txt"
    log_file=open(log_filename,"a+")
    file=open(filename,"rb")
    log_file.write("-------------------------------\n")
    log_file.write("%s send %s to %s\n" % (IP_PORT[0]+" "+str(IP_PORT[1]),filename,RECEIVER_ADDR[0]+" "+str(RECEIVER_ADDR[1])))

    packets=[]
    seq_num=0
    while True:
        data=file.read(512)    #data size
        if not data:
            break
        crc_num=crc16.crc16xmodem(data)    #calculate crc
        pdu=packet.make(seq_num,crc_num,data)    #make packet
        packets.append(pdu)
        seq_num+=1
    num_packets = len(packets)
    log_file.write("total %d packets(512bytes)\n" %(num_packets))
    print('I gots', num_packets)
    #set window size here
    window_size=200
    next_frame_to_send=0

    #start receive ack thread
    THREAD=threading.Thread(target=receive,args=(sock,))
    THREAD.start()
    overtime_flag=0
    scale=50    #using to draw progress bar
    start = time.perf_counter()
    pre=start
    while ack_expected<len(packets):
        mutex.acquire()    #send thread acquire lock
        while next_frame_to_send<ack_expected+window_size:
            if next_frame_to_send>=len(packets):
                break
            #print('Sending packet', next_frame_to_send)
            if overtime_flag==0:
                log_file.write("%s: Send PDU=%d,STATUS=New,ACKed=%d to %s\n" % (time.ctime(),next_frame_to_send,ack_expected,str(RECEIVER_ADDR)))
            elif overtime_flag==1:
                log_file.write("%s: Send PDU=%d,STATUS=TO,ACKed=%d to %s\n" % (time.ctime(),next_frame_to_send,ack_expected,str(RECEIVER_ADDR)))
            send_timer.satrt(next_frame_to_send)
            UDTER.send(packets[next_frame_to_send],sock,RECEIVER_ADDR)
            next_frame_to_send+=1
        overtime_flag=0
        if send_timer.overtime(ack_expected):
            #print("overtime")
            overtime_flag=1
            next_frame_to_send=ack_expected
        
        if (time.perf_counter()-pre) > 1:
            pre=time.perf_counter()
            param = (int) (num_packets/50)
            i = (int) (next_frame_to_send/param)
            a='*' *i
            b='.'*(scale-i)
            c=(i/scale)*100
            dur=pre-start
            print("\r{:^3.0f}%[{}->{}]{:.2f}s".format(c,a,b,dur),end='')
        mutex.release()
    print("\nover")
    UDTER.send(packet.make_empty(), sock, RECEIVER_ADDR)
    log_file.write("send succeed\n") 
    log_file.write("-------------------------------\n\n\n")
    file.close()
    log_file.close()

def receive(sock):

    global mutex
    global ack_expected
    global num_packets
    
    while True:
        ack,_=UDTER.recvack(sock)

        #print('Got Ack',ack)
        if ack>=ack_expected:
            mutex.acquire()
            ack_expected=ack+1
           # print('ack_expected',ack_expected)
            mutex.release()
        if ack_expected>=num_packets:
            break

# receiver.py

import socket
import packet
import crc16
import UDT
import sys
import time
def receive(sock,filename,IP_PORT):
    UDTER=UDT.UDT(0.0001,0.0001)
    file=open(filename,"wb")
    log_filename=IP_PORT[0]+"_"+str(IP_PORT[1])+"_"+"log_file.txt"
    log_file=open(log_filename,"a+")
    log_file.write("-------------------------------\n")
    frame_expected=0
    log_file.write("Receiving %s...\n" %(filename))
    while True:
        pdu,addr=UDTER.recv(sock)
        
        #print(pdu)
        if not pdu:
            break
        seq_num,crc_num,data=packet.extract(pdu)
        
        #print('Got PDU',seq_num)

        crc_expected=crc16.crc16xmodem(data)
        if crc_expected!=crc_num:
            log_file.write("%s: Receive PDU=%d,STATUS=DataErr,FRAME_EXPECTED=%d from %s\n" %(time.ctime(),seq_num,frame_expected,str(addr)))
            #print("data with error")
            continue

        if seq_num==frame_expected:
            #print('Got expected packet')
            log_file.write("%s: Receive PDU=%d,STATUS=OK,FRAME_EXPECTED=%d from %s\n" %(time.ctime(),seq_num,frame_expected,str(addr)))
            #print('Sending ACK', frame_expected)
            UDTER.sendack(frame_expected,sock,addr)
            frame_expected+=1
            file.write(data)
        
        else:
            #print('Got unexpected packet')
            log_file.write("%s: Receive PDU=%d,STATUS=NoErr,FRAME_EXPECTED=%d from %s\n" %(time.ctime(),seq_num,frame_expected,str(addr)))
            #print('Sending ACK', frame_expected-1)
            UDTER.sendack(frame_expected-1,sock,addr)

    print("over")
    log_file.write("Receive succeed\n")
    log_file.write("-------------------------------\n\n\n")
    log_file.close()
    file.close()

视频演示:

GBN-Python演示_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1eL411A7qo/

完整代码:

chris-william0829/gbn-python (github.com) 

  • 4
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值