Socketserver,Event的使用

回顾

网络 IO模型
    1.阻塞IO模型
        多线程 多进程 线程池 进程池  全是阻塞IO
    2.非阻塞IO
        协程是一种非阻塞IO
        1.setblocking(False)  将阻塞修改为非阻塞
        2.一旦是非阻塞 在执行accept recv send 就会立马尝试读写数据 一旦数据没准备好就抛异常
        3.捕获异常
        4.如果没有异常说明数据准备好了 直接处理
        5.捕获到异常 那就做别的事情

        可以实现单线程并发的效果  会大量占用CPU资源

    3.多路复用
        将所有连接交给select来管理  管什么? 管哪个连接可以被处理
        作为处理任务的一方事情变少了  不需要重复不断的问操作系统拿数据  而是等待select返回需要处理的连接
        等待则意味着select是阻塞的

        一  创建连接 和管理连接
        1.创建服务器socket对象
        2.将服务器对象交给select来管理
        3.一旦有客户端发起连接 select将不在阻塞
        4.select将返回一个可读的socket对象(第一次只有服务器)
        5.服务器的可读代表有连接请求 需要执行accept  返回一个客户端连接conn  由于是非阻塞 不能立即去recv
        6.把客户端socket对象也交给select来管理  将conn加入两个被检测的列表中

        7.下一次检测到可读的socket 可能是服务器 也可能客户端 所以加上判断  服务器就accept 客户端就recv
        8.如果检测到有可写(可以send就是系统缓存可用)的socket对象 则说明可以向客户端发送数据了
        7 和 8 执行顺序不是固定的

        二 处理数据收发
        两个需要捕获异常的地方
        1.recv  执行第7步 表示可以读 为什么异常 只有一种可能客户端断开连接
            还需要加上if not 判断是否有数据  ;linux下 对方下线不会抛出异常 会收到空消息
        2.send  执行第8步 表示可以写 为什么异常 只有一种可能客户端断开连接

    异步IO  不仅仅指网络IO 也包括本地IO
        非阻塞IO 和 多路复用 解决都是网络IO的阻塞问题
        本地IO 可以通过子线程 或子进程 来避免阻塞 但是对子线程或子进程而言 依然会阻塞

        最终的解决方案就是协程  asyncio 该模快实现异步IO 内部使用协程实现



    4.异步IO



UDP客户端

import socket

c = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
addr = ("127.0.0.1",9999)

while True:
    msg = input(">>>:")
    c.sendto(msg.encode("utf-8"),addr)

    print(c.recvfrom(1024)[0].decode("utf-8"))


基于TCP的Socketserver

import socketserver
from threading import current_thread
# fork linux下一个多进程接口 windows没有这接口

# 用于处理请求的类
class MyHandler(socketserver.BaseRequestHandler):
    def handle(self):
        print(self)
        print(self.server)  # 获取封装的服务器对象
        print(self.client_address)# 客户端地址
        print(self.request)# 获取客户端的socket对象
        print(current_thread())
        while True:
            data = self.request.recv(1024)
            print(data.decode("utf-8"))
            self.request.send(data.upper())


server = socketserver.ThreadingTCPServer(("127.0.0.1",9999),MyHandler)
server.serve_forever()


基于UDP的Socketserver

import socketserver
from threading import current_thread
# fork linux下一个多进程接口 windows没有这接口
# 用于处理请求的类

class MyHandler(socketserver.BaseRequestHandler):
    def handle(self):
        print(self)
        print(self.server)  # 获取封装的服务器对象
        print(self.client_address)# 客户端地址
        print(self.request)# 是一个元祖 包含收到的数据 和服务器端的socket
        # data,client = self.request

        data = self.request[0]
        print(data.decode("utf-8"))
        self.request[1].sendto(b"i am server",self.client_address)

server = socketserver.ThreadingUDPServer(("127.0.0.1",9999),MyHandler)
server.serve_forever()



# ThreadingUDPServer  在初始化的时候创建了socket对象
# serve_forever() 将sockt注册到select(多路复用的)
# select中返回一个ready  如果为True则可以处理 _handle_request_noblock   内部创建了一个MyHandler的示例  调用了handler函数

#  使用了socket  OOP  多线程

# 正常开发中 如果并发量不大 就是用socketserver
# 否则用协程





"""
使用时的区别:
ThreadingTCPServer
    handler 在连接成功时执行
    self.request 是客户端的socket对象  
    
ThreadingUDPServer
    handler 接收到数据时执行
    self.request  数据和服务器端的socket对象 


"""





客户端

import socket

c = socket.socket()
c.connect(("127.0.0.1",9999))

while True:
    msg = input(">>>:")
    c.send(msg.encode("utf-8"))
    print(c.recv(1024).decode("utf-8"))


Event使用

"""
    事件是什么?
        某件事情发生的信号
    用来干什么?
        在线程间通讯   然而线程本来就能通讯
        作用只有一个就是简化代码

    线程间通讯的例子
    服务器启动需要五秒
    客户端启动后去连接服务器
    去连接服务器必须保证服务器已经开启成功了

    是否启动完成就是要通讯的内容

    注意 Event线程通讯  仅仅用于简单的条件判断  说白了代替bool类型  和if判断
    set() 将状态修改为True
    wati() 等待状态为True才继续执行

"""

# import time
# from threading import Thread
# boot = False
# def server_task():
#     global boot
#     print("正在启动....")
#     time.sleep(5)
#     print("启动....成功")
#     boot = True
#
# def client_task():
#     while True:
#         print("连接服务器....")
#         time.sleep(1)
#         if boot:
#             print("连接成功")
#             break
#         else:
#             print("error 连接失败 服务器未启动!!")
#
# t1 = Thread(target=server_task)
# t1.start()
#
# t2 = Thread(target=client_task)
# t2.start()
#
# t1.join()
# t2.join()




# 使用事件实现

import time
from threading import Thread,Event
event =Event()

def server_task():
    print("正在启动....")
    time.sleep(5)
    print("启动....成功")
    event.set()

def client_task():
    event.wait() #一个阻塞的函数  会阻塞直到对event执行set函数为止
    print("连接成功!")

t1 = Thread(target=server_task)
t1.start()
t2 = Thread(target=client_task)
t2.start()


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值