我们把功能细化,然后用函数包装一下,这样可读性好而且加入新功能的时候也比较容易。
- 实现步骤
- 先把除了import和环境变量部分全部装到run()函数中,并且在最后加入if name == 'main' 部分
- 看run()里面有没有实现某个功能的部分,在run()上面定义该功能的函数,把代码块全部剪切到该函数中
- 看看该函数用到run里的什么变量,作为参数加进去即可
server.py
import socket
import struct
import json
import os.path
# 定义一个共享用文件夹的路径,注意:这部分一般应该写在配置文件中
SHARE_DIR = r'C:\temp'
def get(conn, cmds): # get内容放入函数中
filename = cmds[1]
# 第一步:生成数据的报头信息数据(非固定长度)
header_dic = {
'filename': filename,
'md5': 'xxxx',
'total_size': os.path.getsize(os.path.join(SHARE_DIR, filename))
}
# 将报头encode(网络传输准备)
header_json = json.dumps(header_dic)
header_bytes = header_json.encode('utf-8')
# 第二部:发送报头长度
conn.send(struct.pack('i', len(header_bytes)))
# 第三部:再发报头
conn.send(header_bytes)
# 第四部:最后发真实数据
# 以read的模式读取文件内容(由于用于网络传输,所以是rb模式),并且发送给客户端
with open(os.path.join(SHARE_DIR, filename), 'rb') as f:
# conn.send(f.read()) # 如果文件很大,内存会占满
for line in f: # 这样更加节省内存
conn.send(line)
def run():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(('127.0.0.1', 8080))
server.listen(3)
while True:
conn, addr = server.accept() # 等待连接,连接成功时实例化conn对象用来接下来的通信
while True:
try:
# 收命令
res = conn.recv(1024) # 接收客户端命令(bytes类型),格式get a.txt
if not res: break # 异常处理:防止客户端强制断开连接,导致linux系统死循环
# 解析命令,提取相应命令参数
cmds = res.decode('utf-8').split() # 解码后用空格分割
if cmds[0] == 'get':
get(conn, cmds) # 用函数封装了get的内容
except ConnectionResetError as e:
print(e)
break
conn.close()
server.close()
if __name__ == '__main__': # 这个写法是防止这个py文件被当做模块调用时,执行run()
run()
client.py
import socket
import struct
import json
import os.path
# 定义下载的目录路径,注意:这部分一般应该写在配置文件中
DOWNLOAD_DIR = r'C:\download'
def get(client):
# 接受服务器发来的文件内容,以write模式打开新文件,接受服务端发来的文件内容并写入
# 第一步:先收报头长度(4bytes)的数据
obj = client.recv(4) # 接收服务器发来的,由struct打包的4bytes包
header_size = struct.unpack('i', obj)[0] # 解包,获得报头长度
# 第二部:收报头
header_bytes = client.recv(header_size) # 根据报头长度收报头
# 第三部:从报头中解析出真实数据的描述信息
header_json = header_bytes.decode('utf-8')
header_dic = json.loads(header_json)
total_size = header_dic['total_size']
filename = header_dic['filename']
# 第四部:接受真实收据
with open(os.path.join(DOWNLOAD_DIR, filename), 'wb') as f:
recv_size = 0
while recv_size < total_size: # 循环直到收完指定长度的包
line = client.recv(1024)
f.write(line)
recv_size += len(line)
print('总大小%s,已经下载%s' % (total_size, recv_size)) # 这样我们可以知道进度
def run():
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 8080)) # 连接服务器IP和端口
while True:
# 发命令
cmd = input(">>>>:").strip()
if not cmd:continue
client.send(cmd.encode('utf-8')) # 注意:这部分不需要放在get()函数中,因为发送数据是通用的操作
cmds = cmd.split()
if cmds[0] == 'get':
get(client)
client.close()
if __name__ == '__main__':
run()

浙公网安备 33010602011771号