代码
from socket import *
import struct
import os
def main():
udp_socket = socket(AF_INET, SOCK_DGRAM)
bind_addr = ('', 2018)
ip_portID = ('192.168.0.101', 69)
udp_socket.bind(bind_addr)
msg = struct.pack('!H%dsb5sb' % len(download_filename), 1, download_filename.encode(), 0, 'octet'.encode(), 0)
udp_socket.sendto(msg, ip_portID)
#udp是面向无连接的所以用sendto和recvfrom里面加(ip,port_id);
#tcp则是面向有连接的,使用send和recv后面也不用再加(ip,port_id)
while True:
recv_info,recv_ip_Port_tuple = udp_socket.recvfrom(1024)
#检测服务器是不是随机端口发回来的消息,
#事实证明确实是随机端口,以后发的ack也要往对应的随机端口回而不是69端口
#print (recv_ip_Port_tuple)
recv_data = struct.unpack('!HH', recv_info[:4])
# recv_data是个元祖比如(5,1); 5和1分别占2个Bytes所以 要按 '!HH'格式unpack出来
#申请的文件服务器中不存在的情况
if recv_data[0] == 5:
#打印文件不存在的信息
print (recv_info[4:].decode())
#收到的操作码是3并且块编号是1,创建一个文件并将数据保存,并向随机端口回一个ACK (4,块编号)
elif recv_data[0] == 3:
# 如果是第一块数据
if recv_data[1] == 1:
print (recv_data[1])
f = open(download_filename,'ab')
f.write(recv_info[4:])
#判断是不是最后一块数据,不是就回ack
if len(recv_info) < 516:
break
else:
ack = struct.pack('!HH',4,recv_data[1])
udp_socket.sendto(ack,recv_ip_Port_tuple)
# 收到操作码3且块编号不是1继续保存数据
else:
#打印数据块序号可写可不写
print (recv_data[1])
f.write(recv_info[4:])
#判断是不是最后一块数据,不是就回ack
if len(recv_info) < 516:
break
else:
ack = struct.pack('!HH', 4, recv_data[1])
udp_socket.sendto(ack,recv_ip_Port_tuple)
f.close()
udp_socket.close()
if __name__ == '__main__':
download_filename = input('请输入要下载的文件名(包括后缀):')
if download_filename in os.listdir():
print ('文件已存在或者文件名与当前文件夹中的文件重名!!')
else:
main()