服务端异步IO配合协程浅析

服务端异步IO配合协程浅析

代码如下

#coding:utf-8
import socket
from selectors import DefaultSelector, EVENT_READ, EVENT_WRITE
selector = DefaultSelector()

stopped = False

response = b'HTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n'
response += b'Content-Type: text/plain\r\nContent-Length: 13\r\n'
response += b'hello world'

class Future:
    def __init__(self):
        self.result = None
        self._callback = []

    def add_done_callback(self, fn):
        self._callback.append(fn)

    def set_result(self, result):
        self.result = result
        for fn in self._callback:
            fn(self)

    def __iter__(self):
        yield self
        return self.result


class Task:
    def __init__(self, coro):
        self.coro = coro
        f = Future()
        f.set_result(None)
        self.step(f)

    def step(self, future):
        try:
            next_future = self.coro.send(future.result)
            print("next_future: ", next_future)
        except StopIteration as e:
            print("step stop :", e.value)
            return

        next_future.add_done_callback(self.step)


class ConHandler(object):
    def __init__(self, con, addr):
        self.con = con                                      # 新连接实例
        self.addr = addr                                    # 新连接地址

    def _read_ready(self):
        f = Future()

        def sock_read():                                    # 由于没有解析相应的流协议,所以这里直接接受所有的数据,
                                                            # 如果解析具体协议也可以改写成协程
            all_data = b""                                  # 接受数据
            while True:                                     # 一直接受数据直到数据接受完成
                try:
                    data = self.con.recv(10)
                    if data:
                        print("recv data : ", data)
                        all_data += data
                    else:
                        print("break while")
                        break
                except BlockingIOError:
                    print("BlockingIOError")
                    break
            print("all_data", all_data)
            # selector.unregister(self.con.fileno())
            f.set_result(None)                              # 当数据接受完成后,调用f实例的回调方法,进入将主流程往下执行一步

        selector.register(self.con.fileno(), EVENT_READ, sock_read)     # 注册连接的读事件并注册回调函数
        yield f
        selector.unregister(self.con.fileno())              # 取消连接的注册事件

    def fetch(self):
        # 读事件到来一次读完
        fu = yield from self._read_ready()                  # 调用读数据
        print("recv_data: ", fu)
        # handler  处理请求
        self.response = response*10000
        result = yield from self.sock_send_all()            # 将处理的数据发送出去
        print("send after : ", result)

    def sock_send_all(self):
        send_length = yield from self.sock_send()           # 发送相应数据,返回发送的数据长度
        self.response = self.response[send_length:]         # 减去已经发送的数据长度
        while send_length:                                  # 如果发送长度不为0
            send_length = yield from self.sock_send()       # 继续发送数据
            self.response = self.response[send_length:]     # 减去已经发送的数据长度
        return

    def sock_send(self):
        f = Future()

        def _sock_send():
            con_length = self.con.send(self.response)
            f.set_result(con_length)
        selector.register(self.con.fileno(), EVENT_WRITE, _sock_send)
        send_length = yield f
        selector.unregister(self.con.fileno())
        return send_length


def create_server():
    sock = socket.socket()                                      # 创建连接
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 设置端口重用
    sock.bind(('0.0.0.0', 9003))                                # 设置监听连接端口
    sock.listen(10)                                             # 设置监听缓存区
    sock.setblocking(0)                                         # 设置连接非阻塞

    def sock_accept():                                          # 如果sock的新请求连接处理回调函数
        try:
            conn, addr = sock.accept()                          # 接受新请求
            conn.setblocking(False)                             # 设置接受新连接非阻塞
            print(conn)
        except Exception:
            pass
        Task(ConHandler(conn, addr).fetch())                # 用任务类包裹处理流程,使之流程协程处理

    selector.register(sock.fileno(), EVENT_READ, sock_accept)   # 注册sock的连接读事件并设置读事件的回调函数


def loop():
    while not stopped:
        events = selector.select()                              # 获取触发的事件
        for event_key, event_mask in events:
            callback = event_key.data                           # 获取触发事件的回调函数
            callback()                                          # 执行回调函数

if __name__ == '__main__':
    create_server()
    loop()

基于上一篇的异步协程爬虫,现在服务端的大概原理是:
1.注册服务端连接的读事件和读回调函数,
2.读回调函数,将接受的新请求传入接受处理函数,并包装成Task类执行,
3.注册新连接的读事件,接受完成数据后,调用Task往下执行,
4.处理完成后,将处理的数据写出时,注册新连接的写事件,如果数据未写完继续执行,循环执行,直到数据写出完成
5.取消连接的事件监听
6.继续等待新连接的介入
至此上述代码的执行流程已完成。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TCP/IP服务端异步接收是指在TCP/IP网络通信中,服务端通过使用异步接收的方式来处理客户端发送的数据。 在传统的同步阻塞模型中,服务端通常是通过阻塞式的方式接收客户端的数据。即服务端在接收到客户端的请求后,会阻塞等待,直到接收到完整的数据包后再进行处理。这种方式存在一个问题,即当服务端在接收数据时,无法同时处理其他客户端的请求,从而导致性能瓶颈。 而异步接收的方式可以解决这个问题。在异步模型中,服务端在接收到客户端的连接请求后,不会立即阻塞等待接收数据,而是通过设置回调函数或事件驱动的方式,将数据接收的任务交给操作系统的内核处理。内核会在数据到达时通知服务端,并将数据存储在缓冲区中。服务端则可以在自己的处理逻辑中异步的读取这些缓冲区中的数据。 异步接收的优势在于,服务端可以并发处理多个客户端的请求,提高了系统的吞吐量和响应速度。同时,由于服务端不需要阻塞等待数据的到达,可以灵活地进行其他业务逻辑的处理。 然而,在使用异步接收时也需要注意一些问题。首先,服务端需要合理控制异步接收的并发数,防止资源耗尽。其次,服务端需要及时处理接收到的数据,避免数据的堆积和丢失。此外,异步接收也需要编写相应的异步处理代码,相对于同步方式来说,复杂度更高。 综上所述,TCP/IP服务端异步接收是一种通过利用操作系统内核的异步处理能力,提高服务端并发处理能力和响应性能的方式。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值