Python的网络编程[2] -> TFTP 协议[1] -> TFTP 的 Python 实现
TFTP实现 / TFTP Implement
目录
1 TFTP 的服务器建立过程
服务器建立步骤主要有:
(1) 设定服务器IP和端口号(常用69),建立socket并bind地址;
(2) 设定服务器工作目录;
(3) 建立主循环进行监听,根据收到的信息选择读/写模式;
(4) (建立新的线程及socket)执行上传下载操作;
(5) 下载操作: block number设置为1—打开需要下载的文件—进入循环—读取512byte数据—发送读取的数据—等待ACK报文(超时重发)—确认opcode—确认数据长度是否结束(结束则进行结束处理,并关闭文件)11—block number +1;
(6) 上传操作: block number 设置为0—发送ACK报文—block number +1—打开新的文件存储上传数据—进入循环—等待接收DATA报文—确认opcode—写入数据—发送ACK报文—确认数据长度是否结束(结束则进行结束处理,并关闭文件)—block number +1。
Note: 关于THTP_Helper 的 TFTP 的加解码过程请参考 TFTP 加解码部分
import importlib
from TFTP_Helper import *
import socket
from threading import Thread class TFTPServer():
def __init__(self):
ip = '127.0.0.1'
port = 69
address = (ip, port)
self.home_path = 'TFTPServerFile'
self.server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.server.bind(address) def readRequest(self, file_name, addr):
print('<<< RRQ', '\n=== Read request, starting file %s downing to client' % file_name, end='')
sock_down = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
block_num = 1
try:
f = open(self.home_path + '\\' + file_name, 'rb')
except:
# file no found, exit thread
print('=== File %s no found' % file_name)
exit()
while True:
down_data = f.read(512) # data is byte format
sock_down.sendto(TFTPData.encode(block_num, down_data), addr)
print('>>> DATA', block_num)
ack_msg, ack_addr = sock_down.recvfrom(1024)
print('<<< ACK ', block_num)
opcode, ack_block_num = TFTPAck.decode(ack_msg)
assert opcode == 4 and ack_block_num == block_num, 'Invalid ack message.'
if len(down_data) < 512:
block_num = 1
print('=== Transmission of %s completed' % file_name)
f.close()
exit()
block_num += 1
print('=== Close file')
f.close() def writeRequest(self, file_name, addr):
print('<<< WRQ', '\n=== Write request, starting file %s uploading to server' % file_name)
sock_upload = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
block_num = 0
sock_upload.sendto(TFTPAck.encode(block_num), addr)
print('>>> ACK')
try:
f = open('TFTPServerFIle\\Copy-'+file_name, 'wb')
except:
print('=== File "%s" no found' % file_name)
exit()
block_num += 1
while True:
recv_data, addr = sock_upload.recvfrom(1024)
opcode, block_num_recv, data = TFTPData.decode(recv_data)
print('<<< DATA')
if opcode != 3 or block_num != block_num_recv:
print('=== Error Opcode or Block Number')
# TODO: add error msg send and handle here
exit()
f.write(data)
sock_upload.sendto(TFTPAck.encode(block_num), addr)
print('>>> ACK')
if len(data) < 512:
# TODO: add transmission completed handle here
block_num = 1
print('=== File "%s" transmission completed' % file_name)
f.close()
exit()
block_num += 1 def server_run(self):
while True:
print('=== Waiting client')
msg, addr = self.server.recvfrom(1024)
print('<<< Receive a connection from client %s, msg is %s' % (addr, msg))
opcode, file_name = TFTPReadWriteRequest.decode(msg)
cmdSelect = {1: Thread(target=self.readRequest, args=(file_name, addr)),
2: Thread(target=self.writeRequest, args=(file_name, addr))}
try:
cmdSelect[opcode].start()
except:
print('<<< Receive error opcode%s' % opcode)
raise ErrorOpcode server = TFTPServer()
server.server_run()
2 TFTP 的客户端建立过程
客户端建立步骤主要有:
(1) 获取服务器ip和端口;
(2) 下载操作: 建立下载socket—发送RRQ下载请求—设置block number为1—新建文件存储下载数据—进入循环—等待接收DATA报文—确认opcode—写入数据—发送ACK报文—确认数据长度是否结束(结束则进行结束处理,并关闭文件)—block number +1;
(3) 上传操作: 建立上传socket—发送WRQ上传请求—等待ACK报文—设置block number为0—确认opcode—打开需要上传的文件—进入循环—读取数据—发送DATA报文—接收ACK报文—确认opcode—确认数据长度是否结束(结束则进行结束处理,并关闭文件)—block number +1;
from TFTP_Helper import *
import socket class TFTPClient():
def __init__(self):
server_ip = '127.0.0.1'
port = 69
self.address = (server_ip, port) def readRequest(self, file_name):
sock_down = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
send_data = TFTPReadWriteRequest.encode('r', file_name)
sock_down.sendto(send_data, self.address)
block_num = 1
try:
f = open('TFTPClientFIle\copy-'+file_name, 'wb')
except:
print('--- File "%s" no found' % file_name)
exit()
while True:
recv_data, recv_addr = sock_down.recvfrom(1024)
print('<<< DATA', block_num)
opcode, block_num_recv, data = TFTPData.decode(recv_data)
if opcode != 3 or block_num != block_num_recv:
print('--- Opcode or Block Number Error')
# TODO: add error msg send and handle here
break
f.write(data)
sock_down.sendto(TFTPAck.encode(block_num), recv_addr)
print('>>> ACK ', block_num)
if len(data) < 512:
# TODO: add transmission completed handle here
block_num = 1
print('--- File "%s" transmission completed' % file_name)
f.close()
break
block_num += 1 def writeRequest(self, file_name):
sock_upload = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
send_data = TFTPReadWriteRequest.encode('w', file_name)
sock_upload.sendto(send_data, self.address)
print('>>> WRQ')
recv_data, addr = sock_upload.recvfrom(1024)
print('<<< ACK')
opcode, ack_block = TFTPAck.decode(recv_data)
block_num = 0
if opcode != 4 or ack_block != block_num:
print('--- Error Opcode or Block Number')
# TODO: add error msg send and handle here
exit()
try:
f = open('TFTPClientFIle\\'+file_name, 'rb')
except:
print('--- File "%s" no found' % file_name)
exit()
block_num += 1
while True:
upload_data = f.read(512)
sock_upload.sendto(TFTPData.encode(block_num, upload_data), addr)
print('>>> DATA')
ack_msg, addr = sock_upload.recvfrom(1024)
print('<<< ACK')
opcode, ack_block_num = TFTPAck.decode(ack_msg)
assert opcode == 4 and ack_block_num == block_num, 'Invalid ack message.'
if len(upload_data) < 512:
# TODO: add transmission completed handle here
block_num = 1
print('--- File "%s" transmission completed' % file_name)
f.close()
break
block_num += 1 tftp = TFTPClient()
for file in ['downFile.py', 'downFile.docx', 'downFile.txt', 'downFile.zip']:
tftp.readRequest(file)
for file in ['uploadFile.py', 'uploadFile.docx', 'uploadFile.txt', 'uploadFile.zip']:
tftp.writeRequest(file)
相关阅读
1. TFTP 的基本理论
2. struct 模块
Python的网络编程[2] -> TFTP 协议[1] -> TFTP 的 Python 实现的更多相关文章
- Python的网络编程[3] -> BOOTP 协议[1] -> BOOTP 的 Python 实现
BOOTP实现 / BOOTP Implement 目录 BOOTP 的服务器建立过程 BOOTP 的客户端建立过程 Note: 理论部分请参考文末相关阅读链接 1 BOOTP 的服务器建立过程 服务 ...
- Python的网络编程[4] -> DHCP 协议[1] -> DHCP 的 Python 实现
DHCP实现 / DHCP Implement 目录 DHCP 服务器建立过程 DHCP 报文加码实现过程 下面介绍建立一个简单的DHCP服务器,主要用于对基本的DHCP请求进行响应,目前只提供一个I ...
- Python的网络编程[4] -> DHCP 协议[0] -> DHCP 的基本理论
DHCP协议 / DHCP Protocol 目录 DHCP 基本理论 DHCP 通信流程 DHCP 完整报文 DHCP 的 Optional 字段 DHCP 的报文类型 1 DHCP 基本理论 DH ...
- Python的网络编程[3] -> BOOTP 协议[0] -> BOOTP 的基本理论
BOOTP协议 / BOOTP Protocol 目录 基本理论 BOOTP 与 DHCP 通信流程 数据报文格式 报文加解码实现 1. 基本理论 / Basic Theory BOOTP(Boots ...
- Python的网络编程[6] -> Modbus 协议 -> Modbus 的基本理论与 Python 实现
Modbus协议 / Modbus Protocol 目录 Modbus 协议简介 Modbus RTU协议 Modbus TCP协议与 Python 实现 Modbus 功能码 Modbus TCP ...
- Python的网络编程[1] -> FTP 协议[0] -> FTP 的基本理论
FTP协议 / FTP Protocol FTP全称为File Transfer Protocol(文件传输协议),常用于Internet上控制文件的双向传输,常用的操作有上传和下载.基于TCP/IP ...
- Python的网络编程[1] -> FTP 协议[2] -> 使用 ftplib 建立 FTP 客户端
使用 ftplib 建立 FTP 客户端 用于建立FTP Client,与 pyftplib 建立的 Server 进行通信. 快速导航 1. 模块信息 2. 建立 FTP 客户端 1. 模块信息 1 ...
- Python的网络编程[1] -> FTP 协议[1] -> 使用 pyftplib 建立 FTP 服务器
使用 pyftplib 建立 FTP 服务器 pyftplib 主要用于建立 FTP Server,与 ftplib 建立的 Client 进行通信. 快速导航 1. 模块信息 2. 建立 FTP 服 ...
- python之网络编程
本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类: 消息传递(管道.FIFO.消息队列) 同步(互斥量.条件变量.读写锁.文件和写记录锁.信号量) 共享内存(匿名的和具名的) 远程过程调用 ...
- Python高级网络编程系列之第一篇
在上一篇中我们简单的说了一下Python中网络编程的基础知识(相关API就不解释了),其中还有什么细节的知识点没有进行说明,如什么是TCP/IP协议有几种状态,什么是TCP三次握手,什么是TCP四次握 ...
随机推荐
- katalon系列一:初识Katalon Studio自动化测试工具
最近准备把公司的系统搞上UI自动化,先是自己用Python+selenium+pytest写了一个框架,开始写case的时候发现效率极其慢.原因为: (1)开发为提高前端响应时间,使用前端路由技术,一 ...
- linux path环境变量基础
系统环境变量与个人环境变量的配置文件 系统级别的配置文件: /etc/profile :这个文件预设了几个重要的变量,例如PATH, USER, LOGNAME, MAIL, INPUTRC, HO ...
- Class对象和反射
1.class对象在java中一切都是对象,从某种意义上,java中的对象可以分为:实例对象和Class对象.实例对象通过new关键得到,那么Class对象呢?Class对象无法通过new关键字获取, ...
- STL之deque使用简介
deque函数列表 函数 c.assign(beg,end)c.assign(n,elem) c.at(idx) c.back() c.begin() c.clear() deque<Elem& ...
- HDU 4763 Theme Section ( KMP next函数应用 )
设串为str, 串长为len. 对整个串求一遍next函数,从串结尾开始顺着next函数往前找<=len/3的最长串,假设串长为ans,由于next的性质,所以找到的串肯定满足E……E这种形式, ...
- python基础--用python执行系统命令
from os import system print(system('ping www.baidu.com'))
- 更优雅的清除浮动float方法
上篇文章是利用 :after 方法清除浮动float(作用于浮动元素的父元素上). ; } //为了兼容性,因为ie6/7不能使用伪类,所以加上此行代码. .outer:after {;;visibi ...
- 关于CPU位数,OS位数以及内存大小关系的一点总结
(这个学期做助教,说来好惭愧啊,虽然我也是考研进来的,但是就在两年前复习的资料居然全部都忘光了.对大二的孩子们提问的问题多半都解决不了!!!越来越觉得自己的学习方法有问题了,总是想着一些知识能够根据自 ...
- POJ 2749 Building roads 2-sat+二分答案
把爱恨和最大距离视为限制条件,可以知道,最大距离和限制条件多少具有单调性 所以可以二分最大距离,加边+check #include<cstdio> #include<algorith ...
- 淀粉质模板 Tree
Tree 题目描述 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K 输入输出格式 输入格式: N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 ...