python:初步搞懂了twisted

来源:互联网 发布:autocad2011软件下载 编辑:程序博客网 时间:2024/05/16 03:21

一个最简单的twisted的TCP服务器代码是酱紫的:

from twisted.internet.protocol import Factory, Protocol

from twisted.internet import reactor

 

class my_protocol(Protocol):

    def __init__(self):

        print 'init'

    def __del__(self):

        print 'del'

    def connectionMade(self):

        print 'connectionMade'

    def connectionLost(self, reason):

        print 'connectionLost'

    def dataReceived(self, data):

        print 'dataReceived:%s' % (data)

 

if __name__=='__main__':

    f = Factory()

    f.protocol = my_protocol

    reactor.listenTCP(8080, f)

    reactor.run()

对于reactor,我的理解是:一个非阻塞的单进程单线程的socket服务器,核心采用epoll_wait来等待一个网络事件。网络事件无非是:用户接入(accept),用户断开(close),数据到达。严谨的处理的话,还要考虑发送缓冲区满这样的场景。作为配套的服务,还需要定时器这样的功能。

虽然socket服务器主要都是和IO打交道,但如果IO都是非阻塞的话,CPU的利用率可以很高。

从编程模式上看来,基于网络事件的处理方式表面上很简单,似乎只要在用户接入,用户断开,数据到达等几个事件上写代码就可以了。

实际上,基于事件的模式,其编码远比多线程模式要复杂很多:

   1、服务器必须记录所有客户端当前的状态,本质上来说,要维护一个复杂的状态机;

   2、服务器必须使用定时器来处理资源的回收和超时问题:因为,如果没有定时器,网络事件不触发,对应的代码就永远无法执行到;

   3、业务代码必须短小精悍,不能做长时间的执行,因为这个服务器是单线程的,阻塞意味着其他客户端无法得到处理。(当然,也可以结合多线程,把耗时的任务丢给独立的线程)

   4、业务代码往往没办法从头写到尾,需要大量的状态变量和条件判断来判断:事件触发后,应该从哪个中断点继续执行。

      典型的两个中断是:接收一个大的请求,事件触发时,只得到了一部分数据,这时不得不跳出函数,等待下次数据到达的时候,再将前一次的数据合并到一起。

       第二种中断是:发送大块的数据到客户端,但是发送缓冲区满了。用简单的处理方法的话,可以在一个循环里面轮训发送,直到数据都发送出去,但是极端情况下,这个轮训可能会造成其他客户端阻塞。否则,就只有记录状态,缓冲区腾出空间后,再从未发送的部分开始发送。

 

   再回过头来说这段简单的twisted的TCP服务器代码:

1、每个客户端连接会导致一个my_protocol对象被创建,然后connectionMade事件被触发;

2、数据到达的时候触发dataReceived事件

3、连接断开的时候触发connectionLost事件,然后对象被析构

4、复杂的状态变量,可以放在对象的成员中

5、dataReceived中要写复杂的代码,解决数据分批到达的情况

6、可惜:还没找到关于发送缓冲区满的问题。

#Python