007day_socketserver模块实现多个客户端的上传下载

用socket实现之后就试着用一下socketserver模块

import socketserver
import json
import struct
import os
import hashlib
class Myserver(socketserver.BaseRequestHandler):
    def handle(self) -> None:
        self.options_list={'download':self.download,'upload':self.upload}
        self.conn = self.request
        self.login()
        self.opt_dic = self.my_recv()
        if self.opt_dic['operate'] in self.options_list:
            self.options_list[self.opt_dic['operate']]()


    def get_md5(self,username, password):
        md5 = hashlib.md5(username.encode('utf-8'))
        md5.update(password.encode('utf-8'))
        return md5.hexdigest()

    def my_recv(self):
        leng = self.conn.recv(4)
        msg_dic = self.conn.recv(struct.unpack('i', leng)[0]).decode('utf-8')
        msg = json.loads(msg_dic)
        return msg


    def my_send(self,dic):
        str_dic = json.dumps(dic)
        length = struct.pack('i', len(str_dic))
        self.conn.send(length)
        self.conn.send(str_dic.encode('utf-8'))


    def upload(self):
        msg = self.my_recv()
        with open(msg['filename'], mode='wb') as f:
            while msg['filesize'] > 0:
                content = self.conn.recv(1024)
                msg['filesize'] -= len(content)  # 防止接收信息不够,由于tcp的优化,发送方发送1024个字节,接收时可能会分为几块,每一块多大,这里总长度就减去多少
                f.write(content)


    def download(self):
        abs_path = r'/home/lmh/PycharmProjects/网络编程/tmp'
        filename = os.path.basename(abs_path)
        filesize = os.path.getsize(abs_path)
        dic = {'filename': filename, 'filesize': filesize}
        self.my_send(dic)
        with open(abs_path, mode='rb') as f:
            while filesize > 0:
                content = f.read(1024)
                filesize -= len(content)
                self.conn.send(content)


    def login(self):
        flag = True
        while flag:
            msg = self.my_recv()
            with open(r'/home/lmh/PycharmProjects/网络编程/socketserver模块/userinfo', 'r', encoding='utf-8') as f:
                for line in f:
                    name, pwd = line.strip().split('|')
                    if name == msg['username'] and pwd == self.get_md5(name, msg['password']):
                        res = True
                        flag = False
                        break
                else:
                    res = False
                dic = {'operate': 'login', 'result': res}
                self.my_send(dic)

server = socketserver.ThreadingTCPServer(('127.0.0.1',9001),Myserver)
server.serve_forever() #固定的写法
import socket
import os
import sys
import struct#处理黏包
import json
sk = socket.socket()
sk.connect(('127.0.0.1',9001))

def upload(sk):
    opt_dic = {'operate':'upload'}
    my_send(sk,opt_dic)
    #文件名/文件大小
    abs_path = r'/home/lmh/PycharmProjects/网络编程/tmp'
    filename = os.path.basename(abs_path)
    filesize = os.path.getsize(abs_path)
    dic = {'filename':filename,'filesize':filesize}
    my_send(sk,dic)
    with open(abs_path,mode='rb') as f:
        while filesize>0:
            content = f.read(1024)
            filesize-=len(content)
            sk.send(content)
    sk.close()


def download(sk):
    opt_dic = {'operate':'download'}
    my_send(sk,opt_dic)
    msg=my_recv(sk)
    with open(msg['filename'], mode='wb') as f:
        while msg['filesize'] > 0:
            content = sk.recv(1024)
            msg['filesize'] -= len(content)  # 防止接收信息不够,由于tcp的优化,发送方发送1024个字节,接收时可能会分为几块,每一块多大,这里总长度就减去多少
            f.write(content)
    # sk.close()


def my_send(sk,dic):
    str_dic = json.dumps(dic)
    b_dic = str_dic.encode('utf-8')
    length = struct.pack('i', len(b_dic))
    sk.send(length)
    sk.send(b_dic)


def my_recv(sk):
    length = sk.recv(4)
    msg = sk.recv(struct.unpack('i', length)[0]).decode('utf-8')
    msg = json.loads(msg)
    return msg


'''
登录
'''
def login(sk):
    flag = True
    while flag:
        username = input('用户名:').strip()
        password = input('密 码:').strip()
        dic = {'username': username, 'password': password}
        my_send(sk,dic)
        msg = my_recv(sk)
        if msg['result']:
            print('登录成功')
            flag=False
        else:
            print('登录失败')


login(sk)
# 上传和下载的逻辑
opt_lst=['upload','download']
for index,opt in enumerate(opt_lst,1):
    print(index,opt)

num = int(input('请选择你要操作的序号:'))
if hasattr(sys.modules[__name__],opt_lst[num-1]):
    getattr(sys.modules[__name__],opt_lst[num-1])(sk)


sk.close()

在实现的过程中,server端的函数反射遇到了问题,由于之前都是用的classmethod,这次写反射的过程中由于对对象和类的区分不深刻,总是错误,最后还是用字典去实现反射。

对象是类的实例,类是对象的模板。对象是通过new classname产生的,用来调用类的方法;类的构造方法
classmethod 修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等。如果定义的方法里传了self,在调用的时候也要传self
静态变量 是个所有对象共享的变量 由对象/类调用,但不能重新赋值
绑定方法 自带self参数的函数,由对象调用
类方法 是个自带cls参数的函数 由对象/类调用
class A(object):

    # 属性默认为类属性(可以给直接被类本身调用)
    num = "类属性"

    # 实例化方法(必须实例化类之后才能被调用)
    def func1(self): # self : 表示实例化类后的地址id
        print("func1")
        print(self)

    # 类方法(不需要实例化类就可以被类本身调用)
    @classmethod
    def func2(cls):  # cls : 表示没用被实例化的类本身
        print("func2")
        print(cls)
        print(cls.num)
        cls().func1()

    # 不传递传递默认self参数的方法(该方法也是可以直接被类调用的,但是这样做不标准)
    def func3():
        print("func3")
        print(A.num) # 属性是可以直接用类本身调用的
    
# A.func1() 这样调用是会报错:因为func1()调用时需要默认传递实例化类后的地址id参数,如果不实例化类是无法调用的
A.func2()
A.func3()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值