首页 > 其他 > 详细

第八章 socket网络编程(12):文件传输功能-面向对象优化

时间:2019-08-04 20:04:32      阅读:61      评论:0      收藏:0      [点我收藏+]

这篇我们把之前的代码,用面向对象的形式进行一下优化。

优化的思想:
+ 要使用的参数全在类的内部首先定义,或者从配置文件导入
+ 所有的动作都用类的方法封装(首先需要细化这个功能都有哪些步骤,然后把步骤写入方法,可以直接调用方法作为接口)
> 在函数优化的基础上更容易修改

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

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!