day_socketserver模块实现多个客户端的上传下载
用socket实现之后就试着用一下socketserver模块
1 import socketserver 2 import json 3 import struct 4 import os 5 import hashlib 6 class Myserver(socketserver.BaseRequestHandler): 7 def handle(self) -> None: 8 self.options_list={'download':self.download,'upload':self.upload} 9 self.conn = self.request 10 self.login() 11 self.opt_dic = self.my_recv() 12 if self.opt_dic['operate'] in self.options_list: 13 self.options_list[self.opt_dic['operate']]() 14 15 16 def get_md5(self,username, password): 17 md5 = hashlib.md5(username.encode('utf-8')) 18 md5.update(password.encode('utf-8')) 19 return md5.hexdigest() 20 21 def my_recv(self): 22 leng = self.conn.recv(4) 23 msg_dic = self.conn.recv(struct.unpack('i', leng)[0]).decode('utf-8') 24 msg = json.loads(msg_dic) 25 return msg 26 27 28 def my_send(self,dic): 29 str_dic = json.dumps(dic) 30 length = struct.pack('i', len(str_dic)) 31 self.conn.send(length) 32 self.conn.send(str_dic.encode('utf-8')) 33 34 35 def upload(self): 36 msg = self.my_recv() 37 with open(msg['filename'], mode='wb') as f: 38 while msg['filesize'] > 0: 39 content = self.conn.recv(1024) 40 msg['filesize'] -= len(content) # 防止接收信息不够,由于tcp的优化,发送方发送1024个字节,接收时可能会分为几块,每一块多大,这里总长度就减去多少 41 f.write(content) 42 43 44 def download(self): 45 abs_path = r'/home/lmh/PycharmProjects/网络编程/tmp' 46 filename = os.path.basename(abs_path) 47 filesize = os.path.getsize(abs_path) 48 dic = {'filename': filename, 'filesize': filesize} 49 self.my_send(dic) 50 with open(abs_path, mode='rb') as f: 51 while filesize > 0: 52 content = f.read(1024) 53 filesize -= len(content) 54 self.conn.send(content) 55 56 57 def login(self): 58 flag = True 59 while flag: 60 msg = self.my_recv() 61 with open(r'/home/lmh/PycharmProjects/网络编程/socketserver模块/userinfo', 'r', encoding='utf-8') as f: 62 for line in f: 63 name, pwd = line.strip().split('|') 64 if name == msg['username'] and pwd == self.get_md5(name, msg['password']): 65 res = True 66 flag = False 67 break 68 else: 69 res = False 70 dic = {'operate': 'login', 'result': res} 71 self.my_send(dic) 72 73 server = socketserver.ThreadingTCPServer(('127.0.0.1',9001),Myserver) 74 server.serve_forever() #固定的写法
1 import socket 2 import os 3 import sys 4 import struct#处理黏包 5 import json 6 sk = socket.socket() 7 sk.connect(('127.0.0.1',9001)) 8 9 def upload(sk): 10 opt_dic = {'operate':'upload'} 11 my_send(sk,opt_dic) 12 #文件名/文件大小 13 abs_path = r'/home/lmh/PycharmProjects/网络编程/tmp' 14 filename = os.path.basename(abs_path) 15 filesize = os.path.getsize(abs_path) 16 dic = {'filename':filename,'filesize':filesize} 17 my_send(sk,dic) 18 with open(abs_path,mode='rb') as f: 19 while filesize>0: 20 content = f.read(1024) 21 filesize-=len(content) 22 sk.send(content) 23 sk.close() 24 25 26 def download(sk): 27 opt_dic = {'operate':'download'} 28 my_send(sk,opt_dic) 29 msg=my_recv(sk) 30 with open(msg['filename'], mode='wb') as f: 31 while msg['filesize'] > 0: 32 content = sk.recv(1024) 33 msg['filesize'] -= len(content) # 防止接收信息不够,由于tcp的优化,发送方发送1024个字节,接收时可能会分为几块,每一块多大,这里总长度就减去多少 34 f.write(content) 35 # sk.close() 36 37 38 def my_send(sk,dic): 39 str_dic = json.dumps(dic) 40 b_dic = str_dic.encode('utf-8') 41 length = struct.pack('i', len(b_dic)) 42 sk.send(length) 43 sk.send(b_dic) 44 45 46 def my_recv(sk): 47 length = sk.recv(4) 48 msg = sk.recv(struct.unpack('i', length)[0]).decode('utf-8') 49 msg = json.loads(msg) 50 return msg 51 52 53 ''' 54 登录 55 ''' 56 def login(sk): 57 flag = True 58 while flag: 59 username = input('用户名:').strip() 60 password = input('密 码:').strip() 61 dic = {'username': username, 'password': password} 62 my_send(sk,dic) 63 msg = my_recv(sk) 64 if msg['result']: 65 print('登录成功') 66 flag=False 67 else: 68 print('登录失败') 69 70 71 login(sk) 72 # 上传和下载的逻辑 73 opt_lst=['upload','download'] 74 for index,opt in enumerate(opt_lst,1): 75 print(index,opt) 76 77 num = int(input('请选择你要操作的序号:')) 78 if hasattr(sys.modules[__name__],opt_lst[num-1]): 79 getattr(sys.modules[__name__],opt_lst[num-1])(sk) 80 81 82 sk.close()
在实现的过程中,server端的函数反射遇到了问题,由于之前都是用的classmethod,这次写反射的过程中由于对对象和类的区分不深刻,总是错误,最后还是用字典去实现反射。
```python
对象是类的实例,类是对象的模板。对象是通过new classname产生的,用来调用类的方法;类的构造方法
```
```python
classmethod 修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等。如果定义的方法里传了self,在调用的时候也要传self
```
```python
静态变量 是个所有对象共享的变量 由对象/类调用,但不能重新赋值
绑定方法 自带self参数的函数,由对象调用
类方法 是个自带cls参数的函数 由对象/类调用
```
```python
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()
```

浙公网安备 33010602011771号