檔案傳輸
基礎檔案傳輸(小檔案)
# server端負責接收
import socket
import json
sk = socket.socket()
sk.bind(('127.0.0.1', 5002))
sk.listen()
conn, addr = sk.accept()
msg_f = conn.recv(1024).decode('UTF-8')# 接收client端的檔案資訊
dic_f = json.loads(msg_f)# json.loads()用于將字串形式的資料轉化為字典
with open(dic_f['filename'], mode='wb') as f:
file = conn.recv(dic_f['filesize'])# 以發送過來的檔案大小接收檔案
f.write(file)
conn.close()
sk.close()
##############################################
# client端負責發送
import socket
import os
import json
sk = socket.socket()
sk.connect(('127.0.0.1', 5002))
abs_path = r'D:\1.jpg'
filename = os.path.basename(abs_path)
filesize = os.path.getsize(abs_path)
dic = {'filename': filename, 'filesize': filesize}
str_dic = json.dumps(dic)# json.dumps()用于將字典形式的資料轉化為字串
sk.send(str_dic.encode('UTF-8'))# 將檔案資訊傳遞給server端
with open(abs_path, mode='rb') as f:
file = f.read()
sk.send(file)
sk.close()
- 以上server端負責接收,client端負責發送,運行后在當前目錄下出現1.jpg檔案,
- 以上代碼只能傳輸較小的檔案,且隱患較多,例如當傳輸程序中的str_dic大于1024位元組時,server端接收到的檔案資訊會有誤;且當傳輸大檔案時會出現更多問題,
大檔案傳輸
# 負責接收
import socket
import json
import struct
sk = socket.socket()
sk.bind(('127.0.0.1', 5002))
sk.listen()
conn, addr = sk.accept()
lens = conn.recv(4)
lens = struct.unpack('i', lens)[0]
msg_f = conn.recv(lens).decode('UTF-8')# 接收client端的檔案資訊
dic_f = json.loads(msg_f)# json.loads()用于將字串形式的資料轉化為字典
with open(dic_f['filename'], mode='wb') as f:
while dic_f['filesize'] > 0:
file = conn.recv(1024)
dic_f['filesize'] -= len(file)
f.write(file)
conn.close()
sk.close()
############################################################
# 負責發送
import socket
import os
import json
import struct
sk = socket.socket()
sk.connect(('127.0.0.1', 5002))
abs_path = r'C:\Users\LENOVO\Pictures\Camera Roll\WIN_20200301_14_36_34_Pro.mp4'
filename = os.path.basename(abs_path)
filesize = os.path.getsize(abs_path)
dic = {'filename': filename, 'filesize': filesize}
str_dic = json.dumps(dic)# json.dumps()用于將字典形式的資料轉化為字串
# 為了避免粘包現象
b_dic = str_dic.encode('UTF-8')
lens = struct.pack('i', len(b_dic))# 將要傳輸的檔案資訊的長度轉化為4位元組的形式
sk.send(lens)
sk.send(b_dic)# 將檔案資訊傳遞給server端
with open(abs_path, mode='rb') as f:
# 傳輸大檔案用回圈讀取
while filesize > 0:
file = f.read(1024)# 每次讀取1024位元組
filesize -= 1024
sk.send(file)
sk.close()
- 運行后在當前目錄下出現相應mp4檔案,且為144M較大的檔案,
- 檔案發送比接收快,且發送程序中會將發送的檔案進行拆解,所以當發送1024位元組時,接收端不一定會接收到1024位元組,會出現資料丟失現象,為了避免這種現象,server端接收資料進行回圈時每次減去的資料長度應為每次接收到的資料長度,
- 在傳輸檔案資訊時,可能會出現粘包現象,為了避免出現這種現象,需要先將檔案資訊的長度以4位元組的形式發送給server端,再以相應的長度接收檔案,
客戶端合法性
- 若客戶端要連接服務端要經過合法認證,通過約定的密鑰驗證客戶端合法性,
- 服務端隨機發送資訊給請求連接的客戶端,客戶端將接收到的資訊加上約定的密鑰經過哈希演算法得到一個結果,將此結果發送給服務端,
- 而服務端同時將發送的隨機資訊和密鑰經過哈希演算法得到一個結果,將此結果和接收到客戶端的結果進行比較,若結果一致則通過合法驗證,
- 注意:不能將密鑰通過網路直接發送,這樣可能被攔截,
哈希演算法:通過一個函式,把任意長度的資料轉換為一個長度固定的資料串(通常用16進制的字串表示),即通過摘要函式f()對任意長度的資料data計算出固定長度的摘要digest,目的是為了發現原始資料是否被人篡改過,
# server端
import socket
import os
import hashlib
import hmac
key = b'password'
msg_rand = os.urandom(16)# 生成16位型別bytes的隨機資訊
sk = socket.socket()
sk.bind(('127.0.0.1', 5002))
sk.listen()
conn, addr = sk.accept()
conn.send(msg_rand)# 發送16位隨機資訊
# 根據隨機資訊和密鑰進行摘要
'''
# 采用hashlib模塊中的md5,也可以用sha1
md5 = hashlib.md5(key)
md5.update(msg_rand)
res = md5.hexdigest().encode('UTF-8')# 摘要結果為str型別
'''
# 采用hmac模塊
hm = hmac.new(key, msg_rand)
res = hm.digest()# 此時摘要結果為bytes型別
msg_res = conn.recv(32)
if res == msg_res:
print('合法客戶端')
conn.send(b'hello')
else:
conn.close()
sk.close()
########################################################
# client端
import socket
import hashlib
import hmac
key = b'password'
sk = socket.socket()
sk.connect(('127.0.0.1', 5002))
msg_rand = sk.recv(16)# 接收隨機資訊
'''
md5 = hashlib.md5(key)
md5.update(msg_rand)
res = md5.hexdigest().encode('UTF-8')
'''
hm = hmac.new(key, msg_rand)
res = hm.digest()
sk.send(res)
msg = sk.recv(1024)
print(msg)
sk.close()
sockesever模塊
-
socketsever模塊基于socket模塊,
-
常用于tcp協議的sever端處理并發的客戶請求,
-
此時多個client可與sever端通信,
# sever端 import time import socketserver class Mysever(socketserver.BaseRequestHandler): def handle(self): conn = self.request while True: # 小回圈可發多次訊息 try: msg_r = conn.recv(1024).decode('UTF-8') conn.send(msg_r.upper().encode('UTF-8')) time.sleep(0.5) except ConnectionResetError: break sever = socketserver.ThreadingTCPServer(('127.0.0.1',5002), Mysever) sever.serve_forever()# sever端不主動退出 ###################################################################### # client-n端 import time import socket sk = socket.socket() sk.connect(('127.0.0.1', 5002)) while True: sk.send(b'hello') msg = sk.recv(1024).decode('UTF-8') print(msg)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/167458.html
標籤:Python
上一篇:行程和執行緒的區別
下一篇:使用樹莓派打造一個音樂播放器
