tornado源码分析(三): iostream

tornado iostream篇:
iostream是为了对sokcet异步调用而封装的类, 在后面的httpserver中, tornado会为每一个socket创建一个iostream来对应一个httpconnection
函数如下:
对外有四个函数, 其中主要的read_until, read_bytes, write三个函数
read_until传入两个参数: 读取的结束符和回调函数, 回调函数会把读到的数据作为参数
read_bytes和read_until差不多, 只不过第一个参数是读取的长度
write不用说了就是对socket的写入, 这里要注意的是并不是马上就对socket写入, 而是先写入到缓冲区, 然后改变epoll的状态, 在下一个事件循环中触发写事件再去真正的写入
 
先介绍一个初始化函数
def __init__(self, socket, io_loop=None, max_buffer_size=104857600,
                 read_chunk_size=4096):
        self.socket = socket    //绑定的socket不用说了
        self.socket.setblocking(False)    //设置非阻塞模式
        self.io_loop = io_loop or ioloop.IOLoop.instance()    //ioloop主循环
        self.max_buffer_size = max_buffer_size   //缓冲区大小貌似1G
        self.read_chunk_size = read_chunk_size   //读区块大小默认4K
        self._read_buffer = ""    //读缓冲
        self._write_buffer = ""   //写缓冲
        self._read_delimiter = None    //读取的结束符 http中是\r\n
        self._read_bytes = None        //读取的长度, 当http协议是post时, 按照content-length来读取body内容
        self._read_callback = None    //读回调
        self._write_callback = None   //写回调
        self._close_callback = None   //删除回调
        self._state = self.io_loop.ERROR
        self.io_loop.add_handler(
            self.socket.fileno(), self._handle_events, self._state)  //添加epoll事件

 

再来看一看处理epoll事件的函数, 就是上面的_handle_events:
def _handle_events(self, fd, events):
        if not self.socket:
            logging.warning("Got events for closed stream %d", fd)
            return
        if events & self.io_loop.READ:
            self._handle_read()
        if not self.socket:
            return
        if events & self.io_loop.WRITE:
            self._handle_write()
        if not self.socket:
            return
        if events & self.io_loop.ERROR:
            self.close()
            return
        state = self.io_loop.ERROR
        #如果没有读取完 还需要继续监听READ事件, 
        #如果没有_read_bytes或者_read_delimiter, 则不需要监听读事件
        #这两个值都是外部调用read和write函数时用的
        #在程序运行中其实不太可能存在读写都有的时候,如果真有那么可能程序的逻辑有问题了
        #对于_read_delimiter和_read_bytes也是几乎不会同时存在的
        if self._read_delimiter or self._read_bytes:
            state |= self.io_loop.READ
        if self._write_buffer:
            state |= self.io_loop.WRITE
        if state != self._state:
            self._state = state
            self.io_loop.update_handler(self.socket.fileno(), self._state)

  

看一看读写函数即上文的_handle_read和_handle_write:
    
#读事件, 每次从缓冲区中读取一部分, 默认是4K
    def _handle_read(self):
        try:
            chunk = self.socket.recv(self.read_chunk_size)
        except socket.error, e:
            #过滤掉非阻塞模式时报的错误
            if e[0] in (errno.EWOULDBLOCK, errno.EAGAIN):
                return
            else:
                logging.warning("Read error on %d: %s",
                                self.socket.fileno(), e)
                self.close()
                return
        if not chunk:
            #当收到消息未空时说明连接关闭, 关掉连接
            self.close()
            return
        self._read_buffer += chunk
        if len(self._read_buffer) >= self.max_buffer_size:
            logging.error("Reached maximum read buffer size")
            self.close()
            return
        if self._read_bytes:
            #如果当前缓存长度大于等于给定的读取长度 说明已经读取完毕
            #触发回调函数 清空_read_bytes变量
            if len(self._read_buffer) >= self._read_bytes:
                num_bytes = self._read_bytes
                callback = self._read_callback
                self._read_callback = None
                self._read_bytes = None
                self._run_callback(callback, self._consume(num_bytes))
        elif self._read_delimiter:
            #如果调用了read_until则查找缓冲区的_read_delimiter如果没有则继续等待
            loc = self._read_buffer.find(self._read_delimiter)
            if loc != -1:
                callback = self._read_callback
                delimiter_len = len(self._read_delimiter)
                self._read_callback = None
                self._read_delimiter = None
                self._run_callback(callback,
                                   self._consume(loc + delimiter_len))
# 写函数很简单, 一直写就可以了
    def _handle_write(self):
        while self._write_buffer:
            try:
                num_bytes = self.socket.send(self._write_buffer)
                self._write_buffer = self._write_buffer[num_bytes:]
            except socket.error, e:
                if e[0] in (errno.EWOULDBLOCK, errno.EAGAIN):
                    break
                else:
                    logging.warning("Write error on %d: %s",
                                    self.socket.fileno(), e)
                    self.close()
                    return
        if not self._write_buffer and self._write_callback:
            callback = self._write_callback
            self._write_callback = None
            self._run_callback(callback)
 
这是三个辅助函数, 很简单
    
#读取缓冲区中的数据
    def _consume(self, loc):
        result = self._read_buffer[:loc]
        self._read_buffer = self._read_buffer[loc:]
        return result
    #检查是否关闭
    def _check_closed(self):
        if not self.socket:
            raise IOError("Stream is closed")
    #当当前监听事件不包括需要添加的监听事件时才会更新监听事件
    def _add_io_state(self, state):
        if not self._state & state:
            self._state = self._state | state
            self.io_loop.update_handler(self.socket.fileno(), self._state)
 
下面是三个对外暴露的接口:
#先从缓存中查找结束符, 如果查不到需要添加监听读事件
#read_until和read_bytes都会先到缓冲区里面查找, 如果条件不满足的话 去监听读事件
    def read_until(self, delimiter, callback):
        """Call callback when we read the given delimiter."""
        assert not self._read_callback, "Already reading"
        loc = self._read_buffer.find(delimiter)
        if loc != -1:
            self._run_callback(callback, self._consume(loc + len(delimiter)))
            return
        self._check_closed()
        self._read_delimiter = delimiter
        self._read_callback = callback
        self._add_io_state(self.io_loop.READ)

    def read_bytes(self, num_bytes, callback):
        """Call callback when we read the given number of bytes."""
        assert not self._read_callback, "Already reading"
        if len(self._read_buffer) >= num_bytes:
            callback(self._consume(num_bytes))
            return
        self._check_closed()
        self._read_bytes = num_bytes
        self._read_callback = callback
        self._add_io_state(self.io_loop.READ)

    #添加数据到写缓冲区里面, 并且改变监听事件为写事件,
    #在下一个事件循环中触发写事件将缓冲区中的内容写到文件描述符中
    def write(self, data, callback=None):
        """Write the given data to this stream.

        If callback is given, we call it when all of the buffered write
        data has been successfully written to the stream. If there was
        previously buffered write data and an old write callback, that
        callback is simply overwritten with this new callback.
        """
        self._check_closed()
        self._write_buffer += data
        self._add_io_state(self.io_loop.WRITE)
        self._write_callback = callback

iostream大概就这样, 相比来说还算比较简单, 下一篇的httpserver是重点, 也是难点, 不过把iostream和ioloop和http协议理解了也就不难了

转载于:https://www.cnblogs.com/nobuta/archive/2013/04/19/3031553.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值