1、基於socket庫 TCP 協議實現普通小文件上傳
客戶端代碼:
# tcp_small_file_client.py
import socket
import os
import json
client = socket.socket()
client.connect(('127.0.0.1', 9090))
menu = {"1":"upload","2":"download","3":"exit"}
for key,val in menu.items():
print(key, val)
while True:
option = input('請輸入功能:')
if option == '1':
file_path = input('請輸入要上傳文件的絕對路徑:')
file_name = os.path.basename(file_path)
with open(file_path,'r') as f:
file_data = f.read()
dic = {"option":"1","name":file_name,"data":file_data}
client.send(json.dumps(dic).encode())
msg = client.recv(1024)
if msg.decode() == 'ok':
print('上傳完成...')
elif option == '2':
print('暫未開放...')
elif option == '3':
break
else:
print('不支持的功能,請重新輸入。')
client.close()
服務端代碼:
# tcp_small_file_server.py
import socket
import os
import json
server = socket.socket() # 默認就是tcp
server.bind(('127.0.0.1', 9090))
server.listen()
print('服務啓動...')
while True:
conn, addr = server.accept()
print('新的客戶端:', addr)
while True:
try:
data = conn.recv(2048)
dic = json.loads(data.decode())
if dic.get('option') == '1':
base_path = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(base_path,dic.get('name'))
with open(file_path,'w') as f:
f.write(dic.get('data'))
conn.send('ok'.encode())
except Exception as e:
print('有連接出現異常斷開:', str(e))
break
conn.close()
server.close()
運行:
先運行服務端
python tcp_small_file_server.py
再運行客戶端,並輸入對於的功能上傳文件
python tcp_small_file_client.py
2、基於socket庫 TCP 協議實現大文件上傳,並引入進度條
客戶端代碼:
# tcp_big_file_client.py
import socket
import os
import json
import time
def print_bar1(percent):
bar = '\r' + '*' * int((percent * 100)) + ' %3.0f%%|' % (percent*100) + '100%'
print(bar, end='', flush=True)
client = socket.socket()
client.connect(('127.0.0.1', 9090))
menu = {"1":"upload","2":"download","3":"exit"}
for key,val in menu.items():
print(key, val)
while True:
option = input('請輸入功能:')
if option == '1':
file_path = input('請輸入要上傳文件的絕對路徑:')
file_name = os.path.basename(file_path)
file_size = os.path.getsize(file_path)
dic = {"option":"1","name":file_name,"file_size":file_size}
client.send(json.dumps(dic).encode())
msg = client.recv(100) # 判斷服務端準備好接收文件了,還可以防止粘包
begin_size = file_size
if msg.decode() == 'ok':
# 服務端表示準備好接收文件了,開始循環發送文件
with open(file_path, 'rb') as f:
while file_size:
content = f.read(1024)
client.send(content)
file_size -= len(content)
print_bar1(round((begin_size - file_size) / begin_size, 2))
print('')
elif option == '2':
print('暫未開放...')
elif option == '3':
break
else:
print('不支持的功能,請重新輸入。')
client.close()
服務端代碼:
# tcp_big_file_server.py
import socket
import os
import json
import time
server = socket.socket() # 默認就是tcp
server.bind(('127.0.0.1', 9090))
server.listen()
print('服務啓動...')
while True:
conn, addr = server.accept()
print('新的客戶端:', addr)
while True:
try:
data = conn.recv(2048)
dic = json.loads(data.decode())
if dic.get('option') == '1':
base_path = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(base_path,dic.get('name'))
conn.send('ok'.encode()) # 告訴客戶端,準備好接收文件了
# 準備接收發來的文件內容
with open(file_path, 'ab') as f:
while dic['file_size']:
content = conn.recv(1024)
f.write(content)
dic['file_size'] -= len(content)
except Exception as e:
print('有連接出現異常斷開:', str(e))
break
conn.close()
server.close()
運行同上,先運行服務端,再運行客戶端。這次不同的時客戶端有上傳進度條,可視化查看上傳進度。
3、基於socket庫 TCP 協議實現大文件上傳,並支持斷點續傳
客戶端代碼:
# tcp_continue_big_file_client.py
import socket
import os
import json
import time
def print_bar1(percent):
bar = '\r' + '*' * int((percent * 100)) + ' %3.0f%%|' % (percent*100) + '100%'
print(bar, end='', flush=True)
client = socket.socket()
client.connect(('127.0.0.1', 9090))
menu = {"1":"upload","2":"download","3":"exit"}
for key,val in menu.items():
print(key, val)
while True:
option = input('請輸入功能:')
if option == '1':
file_path = input('請輸入要上傳文件的絕對路徑:')
file_name = os.path.basename(file_path)
file_size = os.path.getsize(file_path)
dic = {"option":"1","name":file_name,"file_size":file_size}
client.send(json.dumps(dic).encode())
file_seek = int(client.recv(100).decode())
if file_seek == file_size:
print('文件已經存在服務端,退出此次傳輸...')
else:
new_size = file_size - file_seek
begin_size = new_size
# 服務端表示準備好接收文件了,開始循環發送文件
with open(file_path, 'rb') as f:
f.seek(file_seek)
while new_size:
content = f.read(1024)
client.send(content)
new_size -= len(content)
print_bar1(round((begin_size - new_size) / begin_size, 2))
time.sleep(0.2)
print('')
elif option == '2':
pass
elif option == '3':
print('暫未開放...')
else:
print('不支持的功能,請重新輸入。')
client.close()
服務端代碼:
# tcp_continue_big_file_server.py
import socket
import os
import json
import time
server = socket.socket() # 默認就是tcp
server.bind(('127.0.0.1', 9090))
server.listen()
print('服務啓動...')
while True:
conn, addr = server.accept()
print('新的客戶端:', addr)
while True:
try:
is_conn = True
data = conn.recv(2048)
dic = json.loads(data.decode())
if dic.get('option') == '1':
base_path = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(base_path,dic.get('name'))
if os.path.exists(file_path):
file_seek = os.path.getsize(file_path)
else:
file_seek = 0
# 將文件指針發送過去,同時也可以解決粘包
conn.send(str(file_seek).encode())
if file_seek == dic['file_size']:
print('文件已經傳輸完成,退出此次傳輸...')
else:
# 重新設置需要接收的文件大小
new_size = dic['file_size'] - file_seek
# 準備接收發來的追加文件內容
with open(file_path, 'ab') as f:
while new_size:
content = conn.recv(1024)
f.write(content)
new_size -= len(content)
# 因爲Python中recv()是阻塞的,只有連接斷開或異常時,接收到的是b''空字節類型,因此需要判斷這種情況就斷開連接。
if content == b'':
is_conn = False
break
if not is_conn:
print('有連接客戶端斷開...')
break
except Exception as e:
print('有連接出現異常斷開:', str(e))
break
conn.close()
server.close()
運行同上,先運行服務端,再運行客戶端。這次不同的時客戶端有上傳進度條,可視化查看上傳進度。
這裏爲了要測試斷點續傳,在客戶端代碼中每發一次數據都會停頓0.2秒,在測試上傳時,在進度條還沒完成就手動kill調客戶端。去看看服務端看文件存到什麼程度了,再次運行客戶端上傳上一次爲傳輸完成的文件,等傳輸完成後。再去服務端看目標文件是否完整、有效。
好了,到這裏就基本完成我們需要的功能,小夥伴們可以在本地做測試,筆者的環境是Ubuntu + Python3.8。有興趣的小夥伴可以把下載功能實現了,有啥問題大家可以多交流學習。