eventloop.py


#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright 2013-2015 clowwindy
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

# from ssloop
# https://github.com/clowwindy/ssloop

from __future__ import absolute_import, division, print_function, \
    with_statement

import os
import time
import socket
import select
import traceback
import errno
import logging
from collections import defaultdict

from shadowsocks import shell

__all__ = ['EventLoop', 'POLL_NULL', 'POLL_IN', 'POLL_OUT', 'POLL_ERR',
           'POLL_HUP', 'POLL_NVAL', 'EVENT_NAMES'] #要传递出去 主要是EventLoop类
#而LT只要我们没有取完缓冲区的数据,就会一直触发。
POLL_NULL = 0x00
POLL_IN = 0x01
POLL_OUT = 0x04
POLL_ERR = 0x08
POLL_HUP = 0x10
POLL_NVAL = 0x20
'''

EVENT_NAMES = {
    POLL_NULL: 'POLL_NULL',     # 事件为空
    POLL_IN: 'POLL_IN',            # 有数据可读
    POLL_OUT: 'POLL_OUT',        # 写数据不会导致阻塞
    POLL_ERR: 'POLL_ERR',        # 指定的文件描述符发生错误(revents 域)
    POLL_HUP: 'POLL_HUP',        # 指定的文件描述符挂起事件
    POLL_NVAL: 'POLL_NVAL',        # 指定的文件描述符非法
}
'''

EVENT_NAMES = {
    POLL_NULL: 'POLL_NULL',
    POLL_IN: 'POLL_IN',
    POLL_OUT: 'POLL_OUT',
    POLL_ERR: 'POLL_ERR',
    POLL_HUP: 'POLL_HUP',
    POLL_NVAL: 'POLL_NVAL',
}

# we check timeouts every TIMEOUT_PRECISION seconds
TIMEOUT_PRECISION = 10

#晚点看
class KqueueLoop(object):#提供类似于epoll的接口 一样的输入 一样的输出  即一样的原型

    MAX_EVENTS = 1024

    def __init__(self):
        self._kqueue = select.kqueue()
        self._fds = {}

    def _control(self, fd, mode, flags):
        events = []
        if mode & POLL_IN:
            events.append(select.kevent(fd, select.KQ_FILTER_READ, flags))
        if mode & POLL_OUT:
            events.append(select.kevent(fd, select.KQ_FILTER_WRITE, flags))
        for e in events:
            self._kqueue.control([e], 0)

    def poll(self, timeout):
        if timeout = TIMEOUT_PRECISION:#超时也会清楚
                for callback in self._periodic_callbacks:#列表里加上callback 取出来逐个处理 注意原型里没有形参
                    callback()#对于dns而言 就是调用dnsresolver.handle_periodic() 也就是dnsresolver._cache.sweep() 属性的缓存的sweep方法  这里直接上就是清理队列 时间戳是再计算
                self._last_time = now

                #对于dnsresolver来说 注册的定期回调是清楚lrucache的超时缓存  这里epoll处理了一轮事件后,就会查看情况并清理lru缓存

    def __del__(self):
        self._impl.close()#停止轮询

# from tornado
def errno_from_exception(e):
    """Provides the errno from an Exception object.

    There are cases that the errno attribute was not set so we pull
    the errno out of the args but if someone instatiates an Exception
    without any args you will get a tuple error. So this function
    abstracts all that behavior to give you a safe way to get the
    errno.
    """

    if hasattr(e, 'errno'):
        return e.errno
    elif e.args:#返回元组第一个元素
        return e.args[0]
    else:
        return None

# from tornado
def get_sock_error(sock):
    error_number = sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
    return socket.error(error_number, os.strerror(error_number))#返回了套接字的错误


发表评论