传输文件简单版
server端:
import socket
import struct
import json
import os
share_dir = r'C:\py3Project\路飞\第三模块\第二章网络编程\05_文件传输\简单版本\server\share'
IP_PORT = ('127.0.0.1', 8999)
def bytes2human(n):
symbols = ('K', 'M', 'G', 'T', 'P', 'E')
prefix = {}
for i, s in enumerate(symbols):
# << 左移” 左移一位表示乘2 即1 << 1=2,二位就表示4 即1 << 2=4,
# 10位就表示1024 即1 << 10=1024 就是2的n次方
prefix[s] = 1 << (i + 1) * 10
for s in reversed(symbols):
if n >= prefix[s]:
value = float(n) / prefix[s]
return '%.2f%s' % (value, s)
return "%sB" % n
def get(conn,file_name):
# 3、以读的方式打开文件,读取文件内容发送给客户端
# 第一步:制作固定长度的报头
print('get')
try:
header_dict = {
'file_name': file_name,
'md5': 'xxx',
'file_size': os.path.getsize(os.path.join(share_dir, file_name))
}
header_json = json.dumps(header_dict, ensure_ascii='False', indent=2)
header_bytes = header_json.encode('utf-8')
# 第二步:先发送报头的长度
conn.send(struct.pack('i', len(header_bytes)))
# 第三步:再发报头
conn.send(header_bytes)
# 第四步:再发送真实的数据
with open(os.path.join(share_dir, file_name), 'rb') as f:
for line in f:
conn.send(line)
except Exception as e:
print(e)
def put(conn, file_name):
"""
接收客户端上传文件
:param conn:
:param file_name:
:return:
"""
# 2、以写的方式打开一个新文件,接收客户端发来的文件的内容写入服务端新文件
# 第一步:先收报头的长度
header_len = conn.recv(4)
header_size = struct.unpack('i', header_len)[0]
# 第二步:再收报头
header_json = conn.recv(header_size).decode('utf-8')
# 第三步:从报头中解析出对真实数据的描述信息
header_dict = json.loads(header_json)
file_size = header_dict['file_size']
file_name = header_dict['file_name']
print(os.path.join(share_dir, file_name))
# 第四步:接收真实的数据,写入文件
with open(os.path.join(share_dir, file_name), 'wb') as f:
recv_size = 0
while recv_size < file_size:
line = conn.recv(1024)
f.write(line)
recv_size += len(line)
print('总大小:%s 已上传大小:%s' % (bytes2human(file_size), bytes2human(recv_size)))
def run():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(IP_PORT)
server.listen(5)
print('starting...')
while True:
conn, addr = server.accept()
print(addr)
while True:
try:
# 1 收命令
res = conn.recv(1024) # b' get a.txt'
if not res:break
# 2、解析命令,提取相应命令参数
cmds = res.decode('utf-8').split() # [get, a.txt]
if cmds[0] == 'get':
get(conn, cmds[1]) # 下载文件
# file_name = cmds[1]
elif cmds[0] == 'put':
put(conn, cmds[1]) # 上传文件
except ConnectionResetError: #适用于windows操作系统
break
conn.close()
server.close()
if __name__ == '__main__':
run()
client端
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import socket
import struct
import json
import os
share_dir = r'C:\py3Project\路飞\第三模块\第二章网络编程\05_文件传输\简单版本\client\download'
IP_PORT = ('127.0.0.1', 8999)
def bytes2human(n):
symbols = ('K', 'M', 'G', 'T', 'P', 'E')
prefix = {}
for i, s in enumerate(symbols):
# << 左移” 左移一位表示乘2 即1 << 1=2,二位就表示4 即1 << 2=4,
# 10位就表示1024 即1 << 10=1024 就是2的n次方
prefix[s] = 1 << (i + 1) * 10
for s in reversed(symbols):
if n >= prefix[s]:
value = float(n) / prefix[s]
return '%.2f%s' % (value, s)
return "%sB" % n
def get(client, file_name):
# 2、以写的方式打开一个新文件,接收服务端发来的文件的内容写入客户的新文件
# 第一步:先收报头的长度
header_len = client.recv(4)
header_size = struct.unpack('i', header_len)[0]
# 第二步:再收报头
header_json = client.recv(header_size).decode('utf-8')
# 第三步:从报头中解析出对真实数据的描述信息
header_dict = json.loads(header_json)
file_size = header_dict['file_size']
file_name = header_dict['file_name']
print(os.path.join(share_dir, file_name))
# 第四步:接收真实的数据,写入文件
with open(os.path.join(share_dir, file_name), 'wb') as f:
recv_size = 0
while recv_size < file_size:
line = client.recv(1024)
f.write(line)
recv_size += len(line)
print('总大小:%s 已下载大小:%s' % (bytes2human(file_size), bytes2human(recv_size)))
def put(client, file_name):
# 向服务端上传文件
print('put')
try:
if not os.path.isfile(os.path.join(share_dir, file_name)):
print('file:%s is not exists' % os.path.join(share_dir, file_name))
return
else:
file_size = os.path.getsize(os.path.join(share_dir, file_name))
header_dict = {
'file_name': file_name,
'md5': 'xxx',
'file_size': file_size
}
header_json = json.dumps(header_dict, ensure_ascii='False', indent=2)
header_bytes = header_json.encode('utf-8')
# 第二步:先发送报头的长度
client.send(struct.pack('i', len(header_bytes)))
# 第三步:再发报头
client.send(header_bytes)
# 第四步:再发送真实的数据
with open(os.path.join(share_dir, file_name), 'rb') as f:
for line in f:
client.send(line)
except Exception as e:
print(e)
def run():
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(IP_PORT)
while True:
# 1、发命令
cmd = input('>> ').strip() # 'get a.txt'
if not cmd:continue
client.send(cmd.encode('utf-8'))
if cmd.startswith('get'):
get(client, cmd.split()[1])
elif cmd.startswith('put'):
put(client, cmd.split()[1])
client.close()
if __name__ == '__main__':
run()
输出结果
sever:
starting...
('127.0.0.1', 19074)
get
get
C:\Users\jingjing\PycharmProjects\py3Project\路飞\第三模块\第二章网络编程\05_文件传输\简单版本\server\share\3.jpeg
总大小:75.36K 已上传大小:1.00K
总大小:75.36K 已上传大小:2.00K
……
总大小:75.36K 已上传大小:75.36K
client:
>> get 1.pptx
C:\py3Project\路飞\第三模块\第二章网络编程\05_文件传输\简单版本\client\download\1.pptx
总大小:970.93K 已下载大小:1.00K
总大小:970.93K 已下载大小:2.00K
……
总大小:970.93K 已下载大小:970.93K
>> put 3.jpeg
put
>>
传输文件优化版
server端:
import socket
import struct
import json
import os
class TCPServer:
IP_PORT = ('127.0.0.1', 8999)
request_queue_size = 5
allow_reuse_address = False
max_packet_size = 8192
share_dir = r'C:\py3Project\路飞\第三模块\第二章网络编程\05_文件传输\简单版本\server\share'
def __init__(self, address=IP_PORT, bind_and_activate=True):
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if bind_and_activate:
try:
self.server.bind(address)
self.server.listen(self.request_queue_size)
print('starting...')
except Exception as e:
self.server.close()
raise e
def get_request(self):
"""Get the request and client address from the socket.
"""
return self.server.accept()
def run(self):
while True:
self.conn, self.client_addr = self.get_request()
print('from client ', self.client_addr)
while True:
try:
# 1 收命令
res = self.conn.recv(self.max_packet_size) # b' get a.txt'
if not res: break
# 2、解析命令,提取相应命令参数
cmds = res.decode('utf-8').split() # [get, a.txt]
if hasattr(self, cmds[0]):
func = getattr(self, cmds[0])
func(cmds[1])
except ConnectionResetError: # 适用于windows操作系统
break
self.conn.close()
self.server.close()
def put(self, file_name):
"""
接收客户端上传文件
:param conn:
:param file_name:
:return:
"""
print('get file %s' % file_name)
# 2、以写的方式打开一个新文件,接收客户端发来的文件的内容写入服务端新文件
# 第一步:先收报头的长度
header_len = self.conn.recv(4)
header_size = struct.unpack('i', header_len)[0]
# 第二步:再收报头
header_json = self.conn.recv(header_size).decode('utf-8')
# 第三步:从报头中解析出对真实数据的描述信息
header_dict = json.loads(header_json)
file_size = header_dict['file_size']
file_name = header_dict['file_name']
print(os.path.join(self.share_dir, file_name))
# 第四步:接收真实的数据,写入文件
with open(os.path.join(self.share_dir, file_name), 'wb') as f:
recv_size = 0
while recv_size < file_size:
line = self.conn.recv(self.max_packet_size)
f.write(line)
recv_size += len(line)
rate = recv_size / file_size * 100
print('总大小:%s 已上传:%%%.2f' % (self.bytes2human(file_size), rate))
@staticmethod
def bytes2human(n):
symbols = ('K', 'M', 'G', 'T', 'P', 'E')
prefix = {}
for i, s in enumerate(symbols):
# << 左移” 左移一位表示乘2 即1 << 1=2,二位就表示4 即1 << 2=4,
# 10位就表示1024 即1 << 10=1024 就是2的n次方
prefix[s] = 1 << (i + 1) * 10
for s in reversed(symbols):
if n >= prefix[s]:
value = float(n) / prefix[s]
return '%.2f%s' % (value, s)
return "%sB" % n
def get(self, file_name):
# 3、以读的方式打开文件,读取文件内容发送给客户端
# 第一步:制作固定长度的报头
print('send file %s' % file_name)
try:
header_dict = {
'file_name': file_name,
'md5': 'xxx',
'file_size': os.path.getsize(os.path.join(self.share_dir, file_name))
}
header_json = json.dumps(header_dict, ensure_ascii='False', indent=2)
header_bytes = header_json.encode('utf-8')
# 第二步:先发送报头的长度
self.conn.send(struct.pack('i', len(header_bytes)))
# 第三步:再发报头
self.conn.send(header_bytes)
# 第四步:再发送真实的数据
with open(os.path.join(self.share_dir, file_name), 'rb') as f:
for line in f:
self.conn.send(line)
except Exception as e:
print(e)
if __name__ == '__main__':
s = TCPServer()
s.run()
client端:
import socket
import struct
import json
import os
class TCPClient:
IP_PORT = ('127.0.0.1', 8999)
request_queue_size = 5
allow_reuse_address = False
max_packet_size = 8192
share_dir = r'C:\py3Project\路飞\第三模块\第二章网络编程\05_文件传输\简单版本\client\download'
def __init__(self, address=IP_PORT, connect=True):
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if connect:
try:
self.client.connect(address)
except Exception as e:
self.client.close()
raise e
def run(self):
while True:
# 1、发命令
inp = input('>> ').strip() # 'get a.txt'
if not inp: continue
self.client.send(inp.encode('utf-8'))
cmd = inp.split()
if hasattr(self, cmd[0]):
func = getattr(self, cmd[0])
func(cmd[1])
client.close()
@staticmethod
def bytes2human(n):
symbols = ('K', 'M', 'G', 'T', 'P', 'E')
prefix = {}
for i, s in enumerate(symbols):
# << 左移” 左移一位表示乘2 即1 << 1=2,二位就表示4 即1 << 2=4,
# 10位就表示1024 即1 << 10=1024 就是2的n次方
prefix[s] = 1 << (i + 1) * 10
for s in reversed(symbols):
if n >= prefix[s]:
value = float(n) / prefix[s]
return '%.2f%s' % (value, s)
return "%sB" % n
def get(self, file_name):
# 2、以写的方式打开一个新文件,接收服务端发来的文件的内容写入客户的新文件
# 第一步:先收报头的长度
header_len = self.client.recv(4)
header_size = struct.unpack('i', header_len)[0]
# 第二步:再收报头
header_json = self.client.recv(header_size).decode('utf-8')
# 第三步:从报头中解析出对真实数据的描述信息
header_dict = json.loads(header_json)
file_size = header_dict['file_size']
file_name = header_dict['file_name']
print(os.path.join(self.share_dir, file_name))
# 第四步:接收真实的数据,写入文件
with open(os.path.join(self.share_dir, file_name), 'wb') as f:
recv_size = 0
while recv_size < file_size:
line = self.client.recv(self.max_packet_size)
f.write(line)
recv_size += len(line)
rate = recv_size / file_size * 100
print('总大小:%s 已下载:%%%.2f' % (self.bytes2human(file_size),rate))
def put(self, file_name):
# 向服务端上传文件
print('put')
try:
if not os.path.isfile(os.path.join(self.share_dir, file_name)):
print('file:%s is not exists' % os.path.join(self.share_dir, file_name))
return
else:
file_size = os.path.getsize(os.path.join(self.share_dir, file_name))
header_dict = {
'file_name': file_name,
'md5': 'xxx',
'file_size': file_size
}
header_json = json.dumps(header_dict, ensure_ascii='False', indent=2)
header_bytes = header_json.encode('utf-8')
# 第二步:先发送报头的长度
self.client.send(struct.pack('i', len(header_bytes)))
# 第三步:再发报头
self.client.send(header_bytes)
# 第四步:再发送真实的数据
with open(os.path.join(self.share_dir, file_name), 'rb') as f:
for line in f:
self.client.send(line)
except Exception as e:
print(e)
if __name__ == '__main__':
c = TCPClient()
c.run()
输出结果:
sever:
starting...
from client ('127.0.0.1', 3500)
send file 3.jpeg
get file 1.pptx
C:\py3Project\路飞\第三模块\第二章网络编程\05_文件传输\简单版本\server\share\1.pptx
总大小:970.93K 已上传:%0.82
……
总大小:970.93K 已上传:%99.96
总大小:970.93K 已上传:%100.00
client:
C:/py3Project/路飞/第三模块/第二章网络编程/05_文件传输/简单版本/client/file_client.py
>> get 3.jpeg
C:\py3Project\路飞\第三模块\第二章网络编程\05_文件传输\简单版本\client\download\3.jpeg
总大小:75.36K 已下载:%10.62
……
总大小:75.36K 已下载:%99.49
总大小:75.36K 已下载:%100.00
>> put 1.pptx
put
>>