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。有兴趣的小伙伴可以把下载功能实现了,有啥问题大家可以多交流学习。