这篇我们把之前的代码,用面向对象的形式进行一下优化。
优化的思想:
+ 要使用的参数全在类的内部首先定义,或者从配置文件导入
+ 所有的动作都用类的方法封装(首先需要细化这个功能都有哪些步骤,然后把步骤写入方法,可以直接调用方法作为接口)
> 在函数优化的基础上更容易修改
server.py
import socket
import struct
import json
import os.path
class TCP_Server:
'''面向对象优化代码'''
share_dir = r'C:\temp'
socket_family = socket.AF_INET
socket_type = socket.SOCK_STREAM
allow_reuse_address = True
request_queue_size = 5
# 初始化,生成套接字对象
def __init__(self, server_addr, bind_and_activate=True):
self.server_addr = server_addr # server是元组类型,内容是ip和port。('127.0.0.1', 8888)
self.socket = socket.socket(self.socket_family, self.socket_type)
if bind_and_activate:
try:
self.server_bind() # 服务器绑定部分的处理,封装入方法
self.server_activate() # 服务器
except:
self.server_close()
raise
# 定义绑定IP和端口
def server_bind(self):
if self.allow_reuse_address:
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind(self.server_addr)
self.server_addr = self.socket.getsockname() # ????
# 定义设置最大等待堆上限
def server_activate(self):
self.socket.listen(self.request_queue_size)
# 定义关闭服务
def server_close(self):
self.socket.close() # 关闭socket服务:clean-up the server
def get_request(self):
return self.socket.accept() # 等待客户端连接。当客户端连接后返回连接对象和客户端地址
# 关闭客户端连接
def close_request(self, request):
request.close() # 关闭与客户端的连接
def get(self, conn, filename): # get内容放入函数中
# 第一步:生成数据的报头信息数据(非固定长度)
header_dic = {
'filename': filename,
'md5': 'xxxx',
'total_size': os.path.getsize(os.path.join(self.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(self.share_dir, filename), 'rb') as f:
# conn.send(f.read()) # 如果文件很大,内存会占满
for line in f: # 这样更加节省内存
conn.send(line)
def run(self):
while True:
self.conn, self.client_addr = self.get_request()
res = self.conn.recv(1024)
while True:
try:
if not res:break
cmds = res.decode('utf-8').split()
if hasattr(self, cmds[0]):
func = getattr(self, cmds[0])
func(self.conn, cmds[1])
except Exception as e:
print(e)
break
tcp_server = TCP_Server(('127.0.0.1', 8888))
tcp_server.run()
client.py
import socket
import struct
import json
import os.path
class TCP_Client:
download_dir = r'C:\download'
def __init__(self, server_addr):
self.server_addr = server_addr
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def client_connect(self):
self.socket.connect(self.server_addr)
def client_close(self):
self.socket.close()
def get(self, _socket):
# 接受服务器发来的文件内容,以write模式打开新文件,接受服务端发来的文件内容并写入
# 第一步:先收报头长度(4bytes)的数据
obj = _socket.recv(4) # 接收服务器发来的,由struct打包的4bytes包
header_size = struct.unpack('i', obj)[0] # 解包,获得报头长度
# 第二部:收报头
header_bytes = _socket.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(self.download_dir, filename), 'wb') as f:
recv_size = 0
while recv_size < total_size: # 循环直到收完指定长度的包
line = _socket.recv(1024)
f.write(line)
recv_size += len(line)
print('总大小%s,已经下载%s' % (total_size, recv_size)) # 这样我们可以知道进度
def run(self):
self.socket.connect(self.server_addr)
while True:
# 发命令
cmd = input(">>>>:").strip()
if not cmd:continue
self.socket.send(cmd.encode('utf-8'))
cmds = cmd.split()
if hasattr(self, cmds[0]):
func = getattr(self, cmds[0])
func(self.socket)
self.close()
tcp_client = TCP_Client(('127.0.0.1', 8888))
tcp_client.run()
第八章 socket网络编程(12):文件传输功能-面向对象优化
原文:https://www.cnblogs.com/py-xiaoqiang/p/11299015.html