angeloce 发表于 2013-1-15 02:44:36

reactor解剖术(2)

 
观看上章的代码, reactor似乎没有主动加入过 reader/writer, reactor如何操作socket的呢?
重新想象reactor在run之前还做过什么?
对了, 连接/建立连接!
 
就如reactor.listenTCP
 
def listenTCP(self, port, factory, backlog=50, interface=''):      p = tcp.Port(port, factory, backlog, interface, self)      p.startListening()      return p 
看看tcp.Port的设计
 
tcp.Port继承于base.BasePort 和 tcp._SocketCloser,
而base.BasePort 继承于abstract.FileDescriptor, 一个抽象的文件操作符类
tcp.Port实例化时没有做太多动作, 我们聚焦在方法 startListening 上
 
# tcp.Port.startListening 生成并绑定了一个socket# 也没有做什么过多的动作, 直接看看最下面的startReadingdef startListening(self):      try:            skt = self.createInternetSocket()            skt.bind((self.interface, self.port))      except socket.error, le:            raise CannotListenError, (self.interface, self.port, le)      # Make sure that if we listened on port 0, we update that to      # reflect what the OS actually assigned us.      self._realPortNumber = skt.getsockname()      log.msg("%s starting on %s" % (self.factory.__class__, self._realPortNumber))      # The order of the next 6 lines is kind of bizarre.If no one      # can explain it, perhaps we should re-arrange them.      self.factory.doStart()      skt.listen(self.backlog)      self.connected = True      self.socket = skt      self.fileno = self.socket.fileno      self.numberAccepts = 100      self.startReading() 
# 一直找到abstract.FileDescriptor.startReading# 执行了reactor.addReaderdef startReading(self):      """Start waiting for read availability.      """      self.reactor.addReader(self)# selectreactor.SelectReactor.addReader指明了# 一个tcp.Port对象被作为reader加入到了reactor的reads队列中def addReader(self, reader):      """      Add a FileDescriptor for notification of data available to read.      """      self._reads = 1 
原来在这里, 在reactor.listenTCP时候就被加入到了reader队列中.
赶紧回头看看, 在 selectreactor.SelectReactor.doSelect中,如果一个类文件操作符状态改变了,会执行其doRead/doWriter方法.那去看看作为reader的tcp.Port的doRead方法.
 
 
# tcp.Port的socket接受了一个连接,# 并执行了self.factory.buildProtocol方法生成一个portocol# 通过self.transport生成了一个tcp.Server对象def doRead(self):      try:            if platformType == "posix":                numAccepts = self.numberAccepts            else:                # win32 event loop breaks if we do more than one accept()                # in an iteration of the event loop.                numAccepts = 1            for i in range(numAccepts):                # we need this so we can deal with a factory's buildProtocol                # calling our loseConnection                if self.disconnecting:                  return                try:                  skt, addr = self.socket.accept()                except socket.error, e:                  if e.args in (EWOULDBLOCK, EAGAIN):                        self.numberAccepts = i                        break                  elif e.args == EPERM:                        # Netfilter on Linux may have rejected the                        # connection, but we get told to try to accept()                        # anyway.                        continue                  elif e.args in (EMFILE, ENOBUFS, ENFILE, ENOMEM, ECONNABORTED):                        log.msg("Could not accept new connection (%s)" % (                            errorcode],))                        break                  raise                protocol = self.factory.buildProtocol(self._buildAddr(addr))                if protocol is None:                  skt.close()                  continue                s = self.sessionno                self.sessionno = s+1                transport = self.transport(skt, protocol, addr, self, s, self.reactor)                transport = self._preMakeConnection(transport)                protocol.makeConnection(transport)            else:                self.numberAccepts = self.numberAccepts+20      except:            log.deferr() 
 
虽然还有点迷糊, 不过知道了protocol对象产生于此处.那这个产生的transport实例具体作用是什么呢?
先看下 protocol.makeConnection
 
# protocol.BaseProtocoldef makeConnection(self, transport):      self.connected = 1      self.transport = transport      self.connectionMade()  
 
看到了一个熟悉的方法connectionMade!
protocol的三个事件方法 connectionMade, dataReceived, connectionLost是protocol最重要的三个方法了.
其一出现了, 剩下的两个是在何处被触发的呢?
 
先不急, 先看看transport 是怎么回事:
 
tcp.Server 来自于 父类 tcp.Connection. 而Connection继承于abstract.FileDescriptor,又是一个类文件符.
tcp.Server实例时还是做了点小动作的
 
# tcp.Serverdef __init__(self, sock, protocol, client, server, sessionno, reactor):      Connection.__init__(self, sock, protocol, reactor)      self.server = server      self.client = client      self.sessionno = sessionno      self.hostname = client      self.logstr = "%s,%s,%s" % (self.protocol.__class__.__name__,                                    sessionno,                                    self.hostname)      self.repstr = "<%s #%s on %s>" % (self.protocol.__class__.__name__,                                          self.sessionno,                                          self.server._realPortNumber)      self.startReading()      self.connected = 1 
self.startReading从 abstract.FileDescriptor上知晓是把 该实例作为reader加入到reactor队列中的.
那我们就看看tcp.Server的doRead方法
 
# tcp.Connectiondef doRead(self):      """Calls self.protocol.dataReceived with all available data.      This reads up to self.bufferSize bytes of data from its socket, then      calls self.dataReceived(data) to process it.If the connection is not      lost through an error in the physical recv(), this function will return      the result of the dataReceived call.      """      try:            data = self.socket.recv(self.bufferSize)      except socket.error, se:            if se.args == EWOULDBLOCK:                return            else:                return main.CONNECTION_LOST      if not data:            return main.CONNECTION_DONE      return self.protocol.dataReceived(data) 
眼前一亮, dataReceived方法!
页: [1]
查看完整版本: reactor解剖术(2)