Day 31基于socketserver实现udp/tcp并发

第九周

Day 31

TCP协议和UDP协议

区别TCPUDP
可靠性对方必须回复一个ack确认信息,才会将自己这端的数据从内存中删除发送一条消息就会立即删除,不管对方是否接收到
有无连接有连接无连接
传输效率效率慢效率高
粘包问题udp协议称之为数据报协议,每次发送都是一个完整的数据报,一个发送唯一对应一个接收(

基于UDP协议的套接字和TCP的区别

区别TCPUDP
配置SOCK_STREAMSOCK_DGRAM
listen
accept(建立连接)
发送sendsendto
接收recvrecvfrom
不允许发空允许发空

基于socketserver模块实现并发udp

 # 并发
import socketserver


class MyRequestHandler(socketserver.BaseRequestHandler):
    def handle(self):  # 处理通信
        data,server=self.request
        server.sendto(data.upper(),self.client_address)

if __name__ == '__main__':
    s = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), MyRequestHandler, bind_and_activate=True)
    s.serve_forever()


# 基础
from socket import *
import time

server = socket(AF_INET, SOCK_DGRAM)
server.bind(('127.0.0.1', 8080))

while True:
    data, client_addr = server.recvfrom(1024)
    time.sleep(10)
    server.sendto(data.upper(), client_addr)

基于socketserver模块实现并发TCP

class MyRequestsHandler(socketserver.BaseRequestHandler):
    def handle(self):  # 处理通信
        while True:
            try:
                data = self.request.recv(1024)
                if len(data) == 0:break
                self.request.send(data.upper())
            except Exception:
                break
            self.request.close()
            
            
if __name__ == '__main__':
    s = socketserver.ThreadingTCPServer(("127.0.0.1", 8080), MyRequestsHandler)
    s.serve_forever()

并发主要是基于方法的使用。

Day 02

元类

控制类的产生(写底层代码时)

1、python中一切皆对象,包括类,

class Teacher:
    def __init__(self,name ,age):
        self.name = name
        self.age = age
        
    def teach(self):
        print("我正在教书!")


teacher = Teacher("dota", 18)  # 调用Teacher类 得到 对象teaccher
							   # 调用元类 得到 Teacher 类

print(type(teacher))
print(type(Teacher))
print(type(teacher.teach))
------------------------------------
>>> <class '__main__.Teacher'>
>>> <class 'type'>
>>> <class 'method'>
	例子中`type(Teacher)`说明`Teacher`本身也是一个对象,可以将其赋值给其他对象,对其添加属性,将其作为函数参数传递等等。

结论:默认的元类是type,默认情况下我们用class关键字定义的类都是由type产生的

那么class关键字都做了那些事情呢?

1、先拿到一个类名

class_name = 'Teacher'

2、然后拿到类的父类

class_bases = (object, ) 根据多继承原则,这里设置为元组

3、在运行类体代码,将产生的名字放在名称空间中

class_dic = {}
class_body = """
    def __init__(self,name ,age):
        self.name = name
        self.age = age
        
    def teach(self):
        print("我正在教书!")
"""
exec(class_body, {}, class_dic)
print(class_dic)
-----------------------------------------
>>> 

4、调用元类(传入类的三大要素:类名、基类、类的名称空间)得到一个元类的对象,然后将元类的对象赋值给变量名Teacher就是我们用class自定义的哪个类

Teacher = type(class_name, class_bases, class_dic)

自定义元类

我们知道了类是通过type方法定义出来的,那么我们可不可以自己定义一个元类呢?答案是肯定的

class Mymeta(type):  # 只有继承了type类的类才是自定义的元类
	pass

这只是自定义元类的一个模板

自定义元类来控制Teacher类的产生,但是我们要给他定义一下规范,那么开始吧。

1、类名必须用驼峰体

2、至少继承一个父类

3、必须要有文件注释,并且注释内容不为空

import re


class Mymeta(type):
    def __init__(self, class_name, class_bases, class_dic):

        if not re.match("[A-Z]", class_name):
            raise BaseException("必须使用驼峰体命名法!")
        if len(class_bases) == 0:
            raise BaseException("必须继承一个父类!")

        doc = class_dic.get("__doc__")  # 获取注释
        if not (doc and len(doc.strip()) > 0):
            # 注释为空 和 有注释,但是注释全部是空格
            raise BaseException("必须要有注释,且注释不能为空!")
          
class Teacher(object, metaclass=Mymeta):
    """
    注释不能为空!
    """
    def __init__(self,name, age):
        self.name = name
        self.age = age

    def teach(self):
        print("我正在讲......")

自定义元类来控制Teacher类的调用

对象是否能被调用,取决于是否有__call__方法

此时我们的元类Mymeta有默认的__call__方法的,那么我们给它定义一个

调用Teacher类做的事情:

  • 先创建一个老师的空对象
  • 调用老师类内的__init__方法,然后将老师的空对象连同括号内的参数的参数一同传给__init__
  • 返回初始化好的老师对象
class Mymeta(type):
    def __init__(self, class_name, class_bases, class_dic):

        if not re.match("[A-Z]", class_name):
            raise BaseException("必须使用驼峰体命名法!")
        if len(class_bases) == 0:
            raise BaseException("必须继承一个父类!")

        doc = class_dic.get("__doc__")  # 获取注释
        if not (doc and len(doc.strip()) > 0):
            # 注释为空 和 有注释,但是注释全部是空格
            raise BaseException("必须要有注释,且注释不能为空!")

    def __call__(self, *args, **kwargs):
        # 创建一个老师的空对象
        teacher_obj = object.__new__(self)  # object类
        # 调用老师类内的__init__函数,然后将老师的空对象连同括号内的参数一同传给__init__
        self.__init__(teacher_obj, *args, **kwargs)
        return teacher_obj
--------------------------------------------------------

注意这里的__call__ 方法其实底层已经定义好了,我们自定义只是为他附加额外的功能,就像下面的私有属性。不定义其实也没有影响,不定义就是按照默认的功能实现

补充:如何将类的对象全部设为私有

通过覆盖实现属性私有

class Mymeta(type):
    def __init__(self, class_name, class_base, class_dic):

        if not re.match("[A-Z]", class_name):
            raise BaseException("命名应该为驼峰体!")

        if len(class_base) == 0:
            raise BaseException("至少继承一个父类!")

        doc = class_dic.get("__doc__")
        if not (doc and len(doc.strip()) > 0):
            raise BaseException("必须要有文件注释,并且注释内容不为空。")

    # res = OldboyTeacher("egon", 18)
    def __call__(self, *args, **kwargs):
        # 1. 先创建一个老师的空对象
        teacher_obj = object.__new__(self)
        # 2.调用老师类内的 __init__函数,然后将老师的空对象连同括号内的参数的参数一同传给__init__
        self.__init__(teacher_obj, *args, **kwargs)           
        # 2.1 获取对象的字典
        # teacher_obj.__dict__
        # 2.2 创建新的对象字典
        # dic = {k:v for k,v in teacher_obj.__dict__}
        # 2.3 将方法(k)设置为私有
        # dic = {"_%s__%s"%(self.__name__, k):v}
        # 2.4 将原来的字典覆盖
        teacher_obj.__dict__ = {"_%s__%s" % (self.__name__, k): v for k, v in teacher_obj.__dict__}

        # 3.将初始化好的老师对象赋值给变量名res
        return teacher_obj

单例模式

单例是一种设计模式,应用该模式的类指挥生成一个示例,单个实例,永远指向一个对象,创建单例模式节约内存

创建单例模式的三种方法

1、基于@classmethod

class MySQL:
    _instance = None  # 初始化单例对象

    def __init__(self, ip, port):  # 自定义的ip和port
        self.ip = ip
        self.port = port

    @classmethod  # 类方法
    def settings(cls):
        if cls._instance:  # 如果存在单例对象
            pass  返回单例对象
        else:  # 没有的话使用自定义的ip和port
            cls._instance = cls("127.0.0.1", 3306)
        return cls._instance
    

# 这里因为需要两个不同的的ip所以 创建两个对象
my1 = MySQL("123.0.0.1", 3306) 
my2 = MySQL("123.0.0.2", 3306)
print(my1, my2)
# 这里就直接使用默认的了
my3 = MySQL.settings()
my4 = MySQL.settings()
print(my3, my4)    
---------------------------------
>>> <__main__.MySQL object at 0x00000255CDF0CFD0> <__main__.MySQL object at 0x00000255CDF0CF60>  # 不同对象
>>> <__main__.MySQL object at 0x00000255CDF0CE10> <__main__.MySQL object at 0x00000255CDF0CE10>  # 相同对象

我们来看看没有 _instance 会怎么样!

    def settings(cls):
        # if cls.__instance:
        #     pass
        # else:
        cls.__instance = cls("127.0.0.1", 3306)
        return cls.__instance
        
my3 = MySQL.settings()
my4 = MySQL.settings()   
---------------------------------
>>> <__main__.MySQL object at 0x000001B6C7B8DF98> <__main__.MySQL object at 0x000001B6C7B8DF60>  # 不同

其实后面两种方法实现的原理是相通的

基于元类

class Mymeta(type):
    _instance = None  # 默认在类内加  _ 表示不想让外界访问

    def __init__(self, class_name, class_bases, class_dic):
        self._instance = object.__new__(self)  # Mysql 类的对象
        self.__init__(self._instance, "120.0.0.1", 3306)

    def __call__(self, *args, **kwargs):
        if args or kwargs:  # 接受了参数
            obj = object.__new__(self)
            self.__init__(obj, *args, **kwargs)
            return obj
        else:  # 没有接收参数 返回原对象
            return self._instance


class MySQL(metaclass=Mymeta):

    def __init__(self, ip, port):
        self.ip = ip
        self.port = port


my1 = MySQL("123.0.0.1", 3306)
my2 = MySQL("123.0.0.2", 3306)
print(my1, my2)
my3 = MySQL()
my4 = MySQL()
print(my3, my4)
--------------------------------
>>> <__main__.MySQL object at 0x0000023595A1DB38> <__main__.MySQL object at 0x0000023595A1DC18>
>>> <__main__.MySQL object at 0x0000023586A6F2B0> <__main__.MySQL object at 0x0000023586A6F2B0>

基于装饰器

def outter(func):
    _instance = func("120.0.0.1", 3306)

    def wrapper(*args, **kwargs):
        if args or kwargs:
            result = func(*args, **kwargs)
            return result
        else:
            return _instance

    return wrapper
    
@outter
class MySQL():

    def __init__(self, ip, port):
        self.ip = ip
        self.port = port


my1 = MySQL("123.0.0.1", 3306)
my2 = MySQL("123.0.0.2", 3306)
print(my1, my2)
my3 = MySQL()
my4 = MySQL()
print(my3, my4) 
-----------------------------------
>>> <__main__.MySQL object at 0x00000196906FEBA8> <__main__.MySQL object at 0x00000196906FEC88>
>>> <__main__.MySQL object at 0x00000196FFFDF278> <__main__.MySQL object at 0x00000196FFFDF278>

Day 03

猴子补丁

纯粹的替换,在使用模块之前替换,不能多次使用

​ 许多代码都用到了json模块,但是json模块的dumpload功能太慢了,于是人们创建了性能更高的ujson模块,那我们只要将原本的两个功能替换成ujson的就好

import json
import ujson

json.load = ujson.load
json.dump = ujson.dump


# 封装一下
def monkey_patch_json():
    json.__name__ = "ujson"  # 重命名
    json.load = ujson.load
    json.dump = ujson.dump


monkey_patch_json()  # 运行一下就能生效了

相对而言这种情况,比如自己创建了一个功能更丰富的模块,除了继承,我们也可以使用猴子补丁

在猴子补丁给我们带来便捷的同事,也有搞乱源代码优雅的风险。

内置函数

内置函数

Builit-in function
abs(x)delattr(ojbect,name)hash()memoryview()set()
all(iterable)dict()help()min()setattr()
any(iterable)dir(object)hex()next()slice()
ascii(object)divmod(a,b)id()object()sorted()
bin(x)enumerate(iterable,start=0)input()oct()staticmethod()
bool(x)eval()int()open()str()
breakpoint(*args,**kwargs)exec()isinstance()ord()sum()
bytearray()filter()issubclass()pow()super()
bytes()float()iter()print()tuple()
callable()format()len()property()type()
chr(i)frozenset()list()range()vars()
@classmethodgetattr()locals()repr()zip()
compile()globals()map()reversed()__import__()
[complex](返回值为real+imag*1j 的辅助,或将字符数字转换成复数)hasattr()max()round()

垃圾回收机制

并发编程

1、程序

程序就是一堆代码文件

2、进程

进程是一个抽象的概念

进程指的是程序的运行过程

3、操作系统

3.1 操作系统的作用

3.2 多道技术

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值