Python3网络编程篇之文件传输案例

普通函数版

目录结构

在这里插入图片描述

settings.ini

[DEFAULT]
share_path = ./share/

Server端代码

#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""简单的文件传输

Server端
"""
import hashlib
import json
import os
import socket
import struct


share_path = r'./share/'


def exit_head(args, addr):

    head_dc = {
        'filename': args,
        'filesize': len(args),
        'source': socket.gethostbyname(socket.gethostname()),
        'destination': str(addr)
    }
    head_json = json.dumps(head_dc)
    head_bytes = bytes(head_json, encoding='utf-8')
    head_len = len(head_bytes)
    fixed = struct.pack('i', head_len)
    return fixed, head_bytes


def make_head(addr, ret):
    print(ret)
    head_dc = {
        'filename': None,
        'filesize': None,
        'filetype': None,
        'md5': None,
        'source': None,
        'destination': None
    }
    head_dc['filename'] = ret[1].decode('utf-8')
    head_dc['filesize'] = os.path.getsize(os.path.join(share_path, ret[1].decode('utf-8')))
    head_dc['filetype'] = os.path.splitext(ret[1])[1].decode('utf-8')
    with open(file=share_path + ret[1].decode('utf-8'), mode='rb') as fp:
        h = hashlib.md5()
        readed_size = 0
        while readed_size < head_dc['filesize']:
            con = fp.read(1024)
            h.update(con)
            readed_size += len(con)
        head_dc['md5'] = h.hexdigest()
    head_dc['source'] = socket.gethostbyname(socket.gethostname())
    head_dc['destination'] = str(addr)
    head_json = json.dumps(head_dc)
    print(head_json)
    head_bytes = head_json.encode(encoding='utf-8')
    fixed = struct.pack('i', len(head_bytes))
    return fixed, head_bytes, head_dc


def get(conn, addr, ret):
    fixed, head_bytes, head_dc = make_head(addr, ret)
    conn.send(fixed)
    conn.send(head_bytes)

    with open(file=share_path + ret[1].decode('utf-8'), mode='rb') as fp:
        readed_size = 0
        while readed_size < head_dc['filesize']:
            con = fp.read(1024)
            conn.send(con)
            readed_size += len(con)
    return True


def put():
    pass


def analysize(conn, addr):

    cmds = conn.recv(1024)
    if not cmds:
        return -1
    if cmds == b'exit':
        # fixed, head_bytes = exit_head(cmds.decode(encoding='utf=8'), addr)
        # conn.send(fixed)
        # conn.send(head_bytes)
        # conn.send(cmds)
        return cmds
    cmd, type = cmds.split(b' ')
    return cmd, type


def connect():
    sk = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
    sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    ip_port = ('', 8080)
    sk.bind(ip_port)
    sk.listen(5)
    conn, addr = sk.accept()
    return conn, addr


def disconnect(conn):
    conn.close()


def judge(*args):
    if args[-1][0] == b'get':
        status = get(args[0], args[1], args[-1])
    else:
        status = put()
    return status


def main():
    while 1:
        conn, addr = connect()
        conn.send(b'Welcome!')
        while 1:
            try:
                ret = analysize(conn, addr)
                if ret is -1:
                    break
                if ret == b'exit':
                    break
                status = judge(conn, addr, ret)
                if status:
                    print('Done!')
                else:
                    print('Failed!')
            except ConnectionResetError:
                break
        disconnect(conn)
    pass


if __name__ == '__main__':
    main()

Client端代码

#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""简单的文件传输

Client端
"""
import hashlib
import json
import os
import socket
import struct
import time

downloads_path = r'./downloads/'


def parse_head(sk):
    fixed = sk.recv(4)
    head_len = struct.unpack('i', fixed)[0]
    head_bytes = sk.recv(head_len)
    print(head_bytes.decode('utf-8'))
    head_dc = json.loads(head_bytes.decode(encoding='utf-8'))
    return head_dc


def get(args):
    sk = args[0]
    cmds = args[1]
    sk.send(cmds.encode(encoding='utf-8'))

    head_dc = parse_head(sk)
    if head_dc['filename'] == 'exit':
        return b'exit'
    file_path = f"{downloads_path}{head_dc['filename']}"
    received_size = 0
    file_size = head_dc['filesize']
    dot = '.'
    lt = '>'
    start = time.perf_counter()
    h = hashlib.md5()
    with open(file=file_path, mode='wb') as fp:
        print('开始下载'.center(100, '='))
        while received_size < file_size:
            con = sk.recv(1024)
            fp.write(con)
            h.update(con)
            received_size += len(con)
            rate = received_size / file_size * 100
            tmp = int(rate)
            print('\r%%%.2f[%s%s]%.2fs' % (rate, tmp * lt, (100 - tmp) * dot, time.perf_counter() - start), end='')
    print()
    if h.hexdigest() != head_dc['md5']:
        os.remove(file_path)
        return False
    print('下载结束'.center(100, '='))
    return True


def put():
    pass


def judge(*args):
    ls = args[1].split()
    if ls[0] == 'get':
        status = get(args)
    elif ls[0] == 'put':
        status = put()
    else:
        args[0].send(b'exit')
        status = b'exit'
    return status


def main():
    sk = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
    ip_port = ('localhost', 8080)
    sk.connect(ip_port)
    print(sk.recv(1024).decode(encoding='utf-8'))

    while 1:
        cmds = input('>>> ').strip()
        status = judge(sk, cmds)
        if status == b'exit':
            break
        if status is True:
            print('Complete!')
        else:
            print('Failed!')
    pass


if __name__ == '__main__':
    main()

面向对象版

目录结构

在这里插入图片描述

Server端代码

#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""简单的文件传输面向对象版

Server端
"""
import json
import os
import socket
import struct
import time


class MyTCPServer(object):
    """

    """
    address_famliy = socket.AF_INET
    protocol_type = socket.SOCK_STREAM
    reuse_address = True
    coding = 'utf-8'
    link_queue_size = 5
    buffer = 1024
    fixed_len_bytes_dc = {
        'i': 4,
        'l': 8
    }
    server_dir = r'./share/'

    def __init__(self, server_address, bind_activate=True):
        self.server_address = server_address
        self.socket = socket.socket(family=self.address_famliy,
                                    type=self.protocol_type)

        if bind_activate:
            try:
                self.server_bind()
                self.server_activate()
            except Exception:
                self.server_close()
                raise

    def server_bind(self):
        if self.reuse_address:
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.bind(self.server_address)
        self.server_address = self.socket.getsockname()

    def server_activate(self):
        self.socket.listen(self.link_queue_size)

    def get_request(self):
        conn, addr = self.socket.accept()
        return conn, addr

    def request_close(self):
        self.conn.close()

    def server_close(self):
        self.socket.close()
        pass

    def run(self):
        while 1:
            self.conn, self.addr = self.get_request()
            print(f'from client: {self.addr}')
            while 1:
                try:
                    head_struct = self.conn.recv(self.fixed_len_bytes_dc['i'])
                    if not head_struct:break
                    head_len = struct.unpack('i', head_struct)[0]
                    head_json = self.conn.recv(head_len).decode(encoding=self.coding)
                    head_dc = json.loads(head_json)
                    cmd = head_dc['cmd']
                    if hasattr(self, cmd):
                        func = getattr(self, cmd)
                        func(head_dc)
                except ConnectionResetError:
                    break
            self.request_close()

    def put(self, args):
        file_path = os.path.abspath(os.path.join(self.server_dir, args['filename']))
        file_size = args['filesize']
        dot = '.'
        lt = '>'
        start = time.perf_counter()
        print('接收开始'.center(100, '='))
        with open(file=file_path, mode='wb') as fp:
            while 1:
                if file_size >= self.buffer:
                    recv_data = self.conn.recv(self.buffer)
                    fp.write(recv_data)
                    file_size -= self.buffer
                else:
                    recv_data = self.conn.recv(file_size)
                    fp.write(recv_data)
                    file_size -= file_size
                    break
                scale = (1 - (file_size / args['filesize'])) * 100
                print('\r%%%.2f[%s%s]%.2fs' % (scale, int(scale) * lt, (100 - int(scale)) * dot, time.perf_counter() - start), end='')

            print()
            print('接收完成'.center(100, '='))


server1 = MyTCPServer(('', 8080))
server1.run()

Client端代码

#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""简单的文件传输面向对象版

Client端
"""
import json
import os
import socket
import struct
import time


class MyTCPClient(object):
    address_family = socket.AF_INET
    protocol_type = socket.SOCK_STREAM
    reuse_address = True
    buffer = 1024
    coding = 'utf-8'
    client_dir = r'./downloads/'

    def __init__(self, server_address, connect=True):
        self.server_address = server_address
        self.socket = socket.socket(self.address_family,
                                    self.protocol_type)
        if connect:
            try:
                self.client_connect()
            except Exception:
                self.client_close()
                raise

    def client_connect(self):
        self.socket.connect(self.server_address)

    def client_close(self):
        self.socket.close()

    def run(self):
        while True:
            inp = input(">>: ").strip()
            if not inp:
                continue
            cmds = inp.split()
            cmd = cmds[0]
            if hasattr(self, cmd):
                func = getattr(self, cmd)
                func(cmds)

    def put(self, args):
        cmd = args[0]
        filename = args[1]
        filepath = os.path.abspath(os.path.join(self.client_dir, filename))
        if not os.path.isfile(filepath):
            print('file:%s is not exists' % filename)
            return
        else:
            filesize = os.path.getsize(filepath)

        head_dic = {'cmd': cmd, 'filename': os.path.basename(filename), 'filesize': filesize}
        print(head_dic)
        head_json = json.dumps(head_dic)
        head_json_bytes = bytes(head_json, encoding=self.coding)

        head_struct = struct.pack('i', len(head_json_bytes))
        self.socket.send(head_struct)
        self.socket.send(head_json_bytes)
        send_size = 0
        dot = '.'
        lt = '>'
        start = time.perf_counter()
        print('上传开始'.center(100, '='))
        with open(file=filepath, mode='rb') as fp:
            while send_size < head_dic['filesize']:
                data = fp.read(self.buffer)
                self.socket.send(data)
                send_size += len(data)
                scale = send_size / head_dic['filesize'] * 100
                print('\r%%%.2f[%s%s]%.2fs' %
                      (
                          scale,
                          int(scale) * lt,
                          (100 - int(scale)) * dot,
                          time.perf_counter() - start
                      ),
                      end=''
                      )
            print()


client = MyTCPClient(('localhost', 8080))
client.run()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值