关于select、poll、epoll的一些体会

题外话

  在驱动select运行的过程中发现了一个有意思的代码,所以先仿造着写了一个demo,主要是下面的那个循环,从对象A中拿到一个属性,当然这个属性得到的输出是一个函数B,然后把对象A传给B,得到结果。总觉得这种操作很NB(sao)

from collections import namedtuple

SelectorKey = namedtuple('SelectorKey', ['fd', 'data'])

sk1 = SelectorKey('123', lambda x: print(x.fd))
sk2 = SelectorKey('456', lambda x: print(x.fd+'456'))

sk_list = [[sk1, Ellipsis], [sk2, Ellipsis]]

if __name__ == '__main__':
    for sl, _ in sk_list:
        callback = sl.data
        callback(sl)

select、poll、epoll的使用

import socket
from selectors import DefaultSelector, EVENT_READ, EVENT_WRITE
selector = DefaultSelector()


class Crawl:
    def connect(self, key):
        """
        当文件描述符可写的时候, key会被select传进来,它是一个SelectorKey对象
        :param key: SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data'])
        :return:
        """
        # 此时不需要监听这个套接字的write方法了
        selector.unregister(key.fd)
        self.client.send('GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n'.format('/', self.host).encode('utf8'))
        selector.register(self.client.fileno(), EVENT_READ, self.read)

    def read(self, key):
        d = self.client.recv(1024)
        """
        # 注意这里不能这么写,因为recv会被阻塞住,导致出错
        while d:
            self.data += d
            d = self.client.recv(1024)
        else:
            selector.unregister(key.fd)
            print(self.data)
        """
        if d:
            self.data += d
        else:
            selector.unregister(key.fd)
            # print(self.data.decode('utf8'))

    def get_url(self):
        self.client = socket.socket()
        self.client.setblocking(False)
        self.host = 'www.baidu.com'
        self.data = b''
        try:
            self.client.connect((self.host, 80))
        except BlockingIOError as e:
            pass
        # 因为下一步是self.client.send,所以是注册可写的状态
        # self.connect是文件描述符可写的时候会调用的方法
        print(self.client.fileno(), 'self.client.fileno()')
        selector.register(self.client.fileno(), EVENT_WRITE, self.connect)


"""
# 这样是无法运行的,因为还需要一个机制去驱动selector的运行
fetcher = Fetcher()
fetcher.get_url()
"""

def loop_forever():
    # 事件循环
    while True:
        # 得到可以操作的socket
        # ready.append((key, events & key.events))-->这个是源码中用于返回的值
        # 从结构可以看出,第一个值为描述符,第二个值表示这个描述符是可读还是可写
        ready = selector.select()
        for key, mask in ready:
            callback = key.data  # key是SelectorKey,表示一个namedtuple,里面存储了函数以及函数需要的参数
            callback(key)


if __name__ == '__main__':
    crawl = Crawl()
    crawl.get_url()
    loop_forever()

套接字可读可写的理解

  更准确的理解应该参考《UNIX 网络编程卷1》中的《第6章 I/O复用》,相关博客
  若有理解错误,望指出,万分感谢。
若有理解错误,望指出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值