python实现文件上传和下载_[Python] socket实现TFTP上传和下载
一、說明
本文主要基于socket實(shí)現(xiàn)TFTP文件上傳與下載。
測試環(huán)境:Win10/Python3.5/tftpd64。
tftpd下載:根據(jù)自己的環(huán)境選擇下載,地址 :http://tftpd32.jounin.net/tftpd32_download.html
主要內(nèi)容:TFTP協(xié)議介紹、程序運(yùn)行圖示和分析fmt、源代碼。
二、TFTP協(xié)議介紹(參考網(wǎng)絡(luò),詳情可搜索)
TFTP(Trivial File Transfer Protocol,簡單文件傳輸協(xié)議),是TCP/IP協(xié)議族中的一個(gè)用來在客戶端與服務(wù)端(C/S架構(gòu))之間進(jìn)行文件傳輸?shù)膮f(xié)議。
1、特點(diǎn):
> 簡單、占用資源少
> 適合小文件傳輸
> 適合在局域網(wǎng)中進(jìn)行傳輸
> 端口號為69
> 基于UDP實(shí)現(xiàn)
2、TFTP下載過程分析:
當(dāng)打開一個(gè)tftpd作為服務(wù)端,會默認(rèn)監(jiān)聽69端口,所以客戶端發(fā)送數(shù)據(jù)到服務(wù)端都是經(jīng)過69端口。
下載的數(shù)據(jù)流過程如上圖所示,客戶端首次發(fā)送需要下載的文件名到服務(wù)端,(文件存在)服務(wù)端收到后會返回該文件的第一個(gè)包,客戶端收到后本地保存然后再發(fā)送ACK應(yīng)答包給服務(wù)端,如此往來多次,一發(fā)一答,即實(shí)現(xiàn)了文件的下載。
3、TFTP操作碼與數(shù)據(jù)格式:
4、差錯碼以及對應(yīng)的提示:
5、TFTP上傳過程分析(此處做簡單文件說明,可參考下面源碼或自行搜索):
上傳的基本流程:客戶端發(fā)送寫請求(操作碼為2)到服務(wù)端,如果可以進(jìn)行上傳,服務(wù)端會返回ACK應(yīng)答包,客戶端收到后即可進(jìn)行第一個(gè)數(shù)據(jù)包發(fā)送,進(jìn)而服務(wù)端收到后會返回ACK應(yīng)打包,如此多次,當(dāng)客戶端文件讀取完成,即可退出上傳,此時(shí)上傳完成。
三、程序運(yùn)行圖示和分析fmt
1、運(yùn)行起來的tftpd服務(wù)端如下所示:
選擇作為下載的路徑和配置IP
2、下載過程:
運(yùn)行腳本傳入兩個(gè)參數(shù):服務(wù)端IP和文件名
3、上傳過程:
4、關(guān)于struct.pack() 和 struct.unpack()的參數(shù)說明:
參考:https://blog.csdn.net/DaxiaLeeSuper/article/details/82018070
struct.pack(b"!H7sb5sb", b"test.png", 0, b"octet", 0 )
主要分析第一個(gè)參數(shù) fmt:如 “!H7sb5sb" => [ 1, b"test.png", 0, b"octet", 0? ]
fmt對后面幾個(gè)參數(shù)說明,其中H代表1,7s表示長度為7的字符串等
1、fmt首個(gè)字符:
2、fmt其他字符:
四、源碼
1 #-*- coding:utf-8 -*-
2
3 """
4 實(shí)現(xiàn) TFTP 上傳與下載功能5 需要配合tftpd 軟件測試6 """
7
8 from socket import *
9 importstruct10 importsys11
12
13 classDownloadClient:14 """
15 下載基本流程:16 --------------------------------------17 客戶端(Client) 服務(wù)端(Server)18 --------------------------------------19 讀寫請求 --->20 22 24 ....25 --------------------------------------26
27 操作碼 功能28 --------------------------------------29 1 讀請求,即下載30 2 寫請求,即上傳31 3 表示數(shù)據(jù)包,即Data32 4 確認(rèn)碼,即ACK33 5 錯誤34 --------------------------------------35 """
36 def __init__(self):37 #讀取參數(shù)
38 if len(sys.argv) != 4:39 print("-" * 30)40 print("Tips:")41 print("python xxx.py 1 127.0.0.1 test.png")42 print("-" * 30)43 exit()44 else:45 self.mid = sys.argv[1] #執(zhí)行的方法,1下載或2上傳
46 self.remoteIp = sys.argv[2] #服務(wù)器IP
47 self.filename = sys.argv[3] #下載文件名
48
49 #創(chuàng)建socket實(shí)例
50 self.socketClient =socket(AF_INET, SOCK_DGRAM)51 self.socketClient.bind(('', 7788))52
53 defstart(self):54 """啟動執(zhí)行"""
55 if self.mid == "1":56 self.download()57 elif self.mid == "2":58 self.upload()59 else:60 print(self.mid)61 print("參數(shù)輸入錯誤 [python 腳本名 方法id(1下載,2上傳) 服務(wù)器IP 文件名]:python xxx.py 1 127.0.0.1 test.png")62 exit()63
64 defdownload(self):65 """TFTP 下載"""
66 print("下載啟動...")67
68 #構(gòu)建下載請求數(shù)據(jù)
69 #第一個(gè)參數(shù) !H7sb5sb = "!H"+str(len(filename))+"sb5sb"
70 filenameLen =str(len(self.filename))71 cmdBuf = struct.pack(("!H%ssb5sb" % filenameLen).encode("utf-8"), 1, self.filename.encode("utf-8"), 0, b"octet", 0)72
73 #發(fā)送下載文件請求數(shù)據(jù)到指定服務(wù)器
74 self.socketClient.sendto(cmdBuf, (self.remoteIp, 69))75
76 #self.show()
77
78 locPackNum = 0 #請求包號
79 saveFile = '' #保存文件句柄
80 whileTrue:81 recvData, recvAddr = self.socketClient.recvfrom(1024)82 recvDataLen =len(recvData)83
84 #解包
85 cmdTuple = struct.unpack(b"!HH", recvData[:4])86 cmd = cmdTuple[0] #指令
87 curPackNum = cmdTuple[1] #當(dāng)前包號
88
89 if cmd == 3: #是否為數(shù)據(jù)包
90 if curPackNum == 1:91 #以追加的方式打開文件
92 saveFile = open(self.filename, "ab")93
94 #包編號是否和上次相等
95 if locPackNum + 1 ==curPackNum:96 saveFile.write(recvData[4:]) #寫入數(shù)據(jù)
97 locPackNum += 1
98
99 #發(fā)送ACK應(yīng)答
100 ackBuf = struct.pack(b"!HH", 4, locPackNum)101 self.socketClient.sendto(ackBuf, recvAddr)102
103 print("(%d)次接收到數(shù)據(jù)" %locPackNum)104
105 #確認(rèn)為最后一個(gè)包
106 if recvDataLen < 516:107 saveFile.close()108 print("已經(jīng)下載完成")109 break
110
111 elif cmd == 5: #是否為錯誤應(yīng)答
112 print("error num:%d" %curPackNum)113 break
114
115 defupload(self):116 """TFTP 上傳"""
117 print("上傳啟動...")118
119 #1、發(fā)送讀請求
120 filenameLen =str(len(self.filename))121 cmdBuf = struct.pack(("!H%ssb5sb" % filenameLen).encode("utf-8"), 2, self.filename.encode("utf-8"), 0, b"octet", 0)122
123 self.socketClient.sendto(cmdBuf, (self.remoteIp, 69))124
125 localPackNum = 1 #本地包號
126 sendFile = '' #文件句柄
127 whileTrue:128 #2、接收回復(fù)
129 recvData, recvAddr = self.socketClient.recvfrom(1024)130
131 #3、解包
132 cmdTuple = struct.unpack(b"!HH", recvData[:4])133 cmd = cmdTuple[0] #指令
134 curPackNum = cmdTuple[1] #當(dāng)前包號
135
136 #print(recvData)
137
138 if cmd == 4:139 #打開并讀取文件
140 if curPackNum ==0:141 sendFile = open(self.filename, "rb")142
143 #ACK應(yīng)答的包號是否與本地的一樣
144 if localPackNum - 1 ==curPackNum:145 #4、讀取 512 byte數(shù)據(jù)
146 sendData = sendFile.read(512)147
148 #判斷文件是否讀取完成
149 if len(sendData) <=0:150 sendFile.close()151 print("上傳完成")152 break
153
154 #5、打包發(fā)送數(shù)據(jù)
155 sendDataBuf = struct.pack(b"!HH512s", 3, localPackNum, sendData)156 self.socketClient.sendto(sendDataBuf, recvAddr)157
158 #打印過程
159 print("(%d)次已發(fā)送,數(shù)據(jù)長度:%d" %(localPackNum, len(sendData)))160 localPackNum += 1
161
162 elif cmd == 5:163 #sendFile.close()
164 print("error num:%d" %curPackNum)165 break
166
167 defshow(self):168 """測試打印數(shù)據(jù)"""
169 recvData = self.socketClient.recvfrom(1024)170 print(recvData)171 exit()172
173
174 if __name__ == "__main__":175 demo =DownloadClient()176 demo.start()
總結(jié)
以上是生活随笔為你收集整理的python实现文件上传和下载_[Python] socket实现TFTP上传和下载的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: python编写安装脚本_LAMP一键安
- 下一篇: python def return 文件
