base de pitón: uso detallado en el reactor marco Python Twisted Event Manager

En este artículo se describe el administrador de eventos en el reactor de uso detallado del marco trenzado de Python, Twisted es un marco de desarrollo de Python asíncrona de una gran popularidad, un amigo en necesidad lata con la referencia
ropa de cama
de mucha práctica, parece que siempre estamos en una situación similar manera de utilizar la programación asincrónica:

Eventos del monitor
eventos ejecuta la correspondiente función de devolución de
llamada de retorno se ha completado (posibles nuevos eventos añadidos a la cola de escucha)
de nuevo a 1, detectar eventos
así que este modo asíncrono se llama el patrón del reactor, como concepto bucle de ejecución en el desarrollo de iOS, de hecho, muy similar al bucle de reactor, evento UI pantalla del monitor hilo principal Run Loop, una vez que el código correspondiente al evento se ejecuta el control de eventos de interfaz de usuario, puede también generar un evento para la ejecución del hilo principal por otros medios GCD. Aquí Insertar imagen Descripción
La figura es una representación del modo de impulso Reactor, diseño Twisted se basa en el patrón de Reactor, programa Twisted es el bucle continuo mientras se espera para el evento, eventos de manipulación.

from twisted.internet import reactor
reactor.run()

reactor Twisted es un programa objeto singleton.

el Reactor
El reactor es el gestor de eventos para el registro, la cancelación del evento, corriendo bucle de eventos, llamar a la función de devolución de llamada de manejar cuando se produce un evento. Hay varias conclusiones sobre el reactor la siguiente:

reactor de retorcido únicamente puede iniciar llamando reactor.run ().
reactor de bucle se ejecuta al comienzo de su proceso, que se ejecuta en el proceso primario.
Una vez iniciado, se ejecutará siempre. reactor estará bajo control de un programa (o en particular bajo el control de un promotor de su rosca).
ciclo del reactor y no consume recursos de la CPU.
No es necesario crear explícitamente un reactor, que acaba de presentar en Aceptar.
Por último, la necesidad de explicar. En Twisted en, el reactor es Singleton (es decir, Singleton), que no es sólo un programa en un reactor, y siempre y cuando se introduce en consecuencia para crear uno. Esta forma de realización es un método para introducir el valor predeterminado por encima de trenzado, por supuesto, hay otros métodos retorcidos el reactor puede ser introducido. Por ejemplo, llamada en lugar encuesta para seleccionar el sistema de método de twisted.internet.pollreactor.

Para utilizar otro reactor, que debe ser instalado antes de la introducción twisted.internet.reactor. El siguiente es un método de pollreactor de montaje:

from twisted.internet import pollreactor
pollreactor.install()

Si usted no tiene que instalar otro reactor especial y twisted.internet.reactor introducido, a continuación, Twisted será basado en el sistema operativo instalar el reactor por defecto. Debido a esto, la práctica habitual de no introducir en el reactor por el módulo superior para evitar la instalación del reactor de forma predeterminada, pero se monta en la región que desee utilizar el reactor.
Aquí está el pollreactor regrabable el procedimiento anterior:

from twited.internet import pollreactor
pollreactor.install()
from twisted.internet import reactor
reactor.run()

A continuación, el reactor es cómo lograr un solo caso? Mirada desde el reactor de importación twisted.internet hacer lo que las cosas y entender.

La siguiente es una parte del código torcido / Internet / reactor.py de:

# twisted/internet/reactor.py
import sys
del sys.modules['twisted.internet.reactor']
from twisted.internet import default
default.install()

Nota: Python todo cargado en módulos de memoria se coloca sys.modules, es un diccionario global. Buscará primero cuando la importación de un módulo en la lista ya está cargado este módulo, si la carga es simplemente añade al nombre del módulo está llamando espacio de nombres de módulo de importación. Si no se ha cargado desde el directorio sys.path para encontrar el nombre del módulo de archivo de módulo, encontrar el módulo se carga en memoria y se añade a los sys.modules, y el nombre en el espacio de nombres actual.

Si estamos ejecuta por primera vez desde el reactor de importación twisted.internet, porque no ha sys.modules twisted.internet.reactor, se ejecutará el código reactory.py, instalar el reactor de forma predeterminada. Después de eso, si importa, porque sys.modules en el módulo ya existe, se sys.modules directamente en twisted.internet.reactor en el espacio de nombres actual.

La instalación por defecto:

注:Python中所有加载到内存的模块都放在sys.modules,它是一个全局字典。当import一个模块时首先会在这个列表中查找是否已经加载了此模块,如果加载了则只是将模块的名字加入到正在调用import的模块的命名空间中。如果没有加载则从sys.path目录中按照模块名称查找模块文件,找到后将模块载入内存,并加入到sys.modules中,并将名称导入到当前的命名空间中。

假如我们是第一次运行from twisted.internet import reactor,因为sys.modules中还没有twisted.internet.reactor,所以会运行reactory.py中的代码,安装默认的reactor。之后,如果导入的话,因为sys.modules中已存在该模块,所以会直接将sys.modules中的twisted.internet.reactor导入到当前命名空间。

default中的install:

Obviamente, por defecto será conseguir la adecuada instalación dependiendo de la plataforma. Bajo Linux será el primero en utilizar epollreactor, si el núcleo no soporta, sólo se puede utilizar pollreactor. Mac plataforma pollreactor, ventanas usar selectreactor. Cada instalación es casi alcanzada, cuando extraemos el selectreactor instalar a la vista.

# twisted/internet/selectreactor.py:
def install():
  """Configure the twisted mainloop to be run using the select() reactor.
  """
  # 单例
  reactor = SelectReactor()
  from twisted.internet.main import installReactor
  installReactor(reactor)

# twisted/internet/main.py:
def installReactor(reactor):
  """
  Install reactor C{reactor}.

  @param reactor: An object that provides one or more IReactor* interfaces.
  """
  # this stuff should be common to all reactors.
  import twisted.internet
  import sys
  if 'twisted.internet.reactor' in sys.modules:
    raise error.ReactorAlreadyInstalledError("reactor already installed")
  twisted.internet.reactor = reactor
  sys.modules['twisted.internet.reactor'] = reactor

En installReactor añadió twisted.internet.reactor clave para sys.modules, se crea valor positivo aislado y luego instalar. Para ser utilizado reactor después, este se introducirá en una única realización.

SelectReactor
# twisted/internet/selectreactor.py
@implementer(IReactorFDSet)
class SelectReactor(posixbase.PosixReactorBase, _extraBase)

implementador implementos SelectReactor expresadas métodos de interfaz IReactorFDSet utiliza aquí zope.interface, es la interfaz en Python, los estudiantes interesados pueden pasar a la siguiente.
IReactorFDSet interactúa principalmente descriptor de adquisición, añadir, borrar o método de operación. Estos métodos podrán ver el nombre para saber el significado, así que no añadir un comentario.

# twisted/internet/interfaces.py
class IReactorFDSet(Interface):

  def addReader(reader):

  def addWriter(writer):

  def removeReader(reader):

  def removeWriter(writer):

  def removeAll():

  def getReaders():

  def getWriters():
reactor.listenTCP()

El ejemplo de la reactor.listenTCP () registró un detector de eventos, es los métodos PosixReactorBase clase padre.

# twisted/internet/posixbase.py
@implementer(IReactorTCP, IReactorUDP, IReactorMulticast)
class PosixReactorBase(_SignalReactorMixin, _DisconnectSelectableMixin,
            ReactorBase):

  def listenTCP(self, port, factory, backlog=50, interface=''):
    p = tcp.Port(port, factory, backlog, interface, self)
    p.startListening()
    return p

# twisted/internet/tcp.py
@implementer(interfaces.IListeningPort)
class Port(base.BasePort, _SocketCloser):
  def __init__(self, port, factory, backlog=50, interface='', reactor=None):
    """Initialize with a numeric port to listen on.
    """
    base.BasePort.__init__(self, reactor=reactor)
    self.port = port
    self.factory = factory
    self.backlog = backlog
    if abstract.isIPv6Address(interface):
      self.addressFamily = socket.AF_INET6
      self._addressType = address.IPv6Address
    self.interface = interface
  ...

  def startListening(self):
    """Create and bind my socket, and begin listening on it.
     创建并绑定套接字,开始监听。

    This is called on unserialization, and must be called after creating a
    server to begin listening on the specified port.
    """
    if self._preexistingSocket is None:
      # Create a new socket and make it listen
      try:
        # 创建套接字
        skt = self.createInternetSocket()
        if self.addressFamily == socket.AF_INET6:
          addr = _resolveIPv6(self.interface, self.port)
        else:
          addr = (self.interface, self.port)
        # 绑定
        skt.bind(addr)
      except socket.error as le:
        raise CannotListenError(self.interface, self.port, le)
      # 监听
      skt.listen(self.backlog)
    else:
      # Re-use the externally specified socket
      skt = self._preexistingSocket
      self._preexistingSocket = None
      # Avoid shutting it down at the end.
      self._shouldShutdown = False

    # Make sure that if we listened on port 0, we update that to
    # reflect what the OS actually assigned us.
    self._realPortNumber = skt.getsockname()[1]

    log.msg("%s starting on %s" % (
        self._getLogPrefix(self.factory), self._realPortNumber))

    # The order of the next 5 lines is kind of bizarre. If no one
    # can explain it, perhaps we should re-arrange them.
    self.factory.doStart()
    self.connected = True
    self.socket = skt
    self.fileno = self.socket.fileno
    self.numberAccepts = 100

    # startReading调用reactor的addReader方法将Port加入读集合
    self.startReading()

Toda la lógica es simple, y el lado del servidor como de costumbre, crea un socket, bind, escucha. Excepto que descriptor de socket añadido al conjunto de lectura de reactor. Así que si la conexión con el cliente a través de las palabras, el reactor será objeto de seguimiento, entonces el controlador de eventos se activa.

reacotr.run () bucle de eventos principal

# twisted/internet/posixbase.py
@implementer(IReactorTCP, IReactorUDP, IReactorMulticast)
class PosixReactorBase(_SignalReactorMixin, _DisconnectSelectableMixin,
            ReactorBase)

# twisted/internet/base.py
class _SignalReactorMixin(object):

  def startRunning(self, installSignalHandlers=True):
    """
    PosixReactorBase的父类_SignalReactorMixin和ReactorBase都有该函数,但是
    _SignalReactorMixin在前,安装mro顺序的话,会先调用_SignalReactorMixin中的。
    """
    self._installSignalHandlers = installSignalHandlers
    ReactorBase.startRunning(self)

  def run(self, installSignalHandlers=True):
    self.startRunning(installSignalHandlers=installSignalHandlers)
    self.mainLoop()

  def mainLoop(self):
    while self._started:
      try:
        while self._started:
          # Advance simulation time in delayed event
          # processors.
          self.runUntilCurrent()
          t2 = self.timeout()
          t = self.running and t2
          # doIteration是关键,select,poll,epool实现各有不同
          self.doIteration(t)
      except:
        log.msg("Unexpected error in main loop.")
        log.err()
      else:
        log.msg('Main loop terminated.')

mianLoop el bucle principal es el último en reciclaje, llamada al método doIteration para el seguimiento de un conjunto de descriptores de leer y escribir, si se descubre que tienen descriptores están dispuestos a leer y escribir, a continuación, llama al controlador de eventos.

# twisted/internet/selectreactor.py
@implementer(IReactorFDSet)
class SelectReactor(posixbase.PosixReactorBase, _extraBase):

  def __init__(self):
    """
    Initialize file descriptor tracking dictionaries and the base class.
    """
    self._reads = set()
    self._writes = set()
    posixbase.PosixReactorBase.__init__(self)

  def doSelect(self, timeout):
    """
    Run one iteration of the I/O monitor loop.

    This will run all selectables who had input or output readiness
    waiting for them.
    """
    try:
      # 调用select方法监控读写集合,返回准备好读写的描述符
      r, w, ignored = _select(self._reads,
                  self._writes,
                  [], timeout)
    except ValueError:
      # Possibly a file descriptor has gone negative?
      self._preenDescriptors()
      return
    except TypeError:
      # Something *totally* invalid (object w/o fileno, non-integral
      # result) was passed
      log.err()
      self._preenDescriptors()
      return
    except (select.error, socket.error, IOError) as se:
      # select(2) encountered an error, perhaps while calling the fileno()
      # method of a socket. (Python 2.6 socket.error is an IOError
      # subclass, but on Python 2.5 and earlier it is not.)
      if se.args[0] in (0, 2):
        # windows does this if it got an empty list
        if (not self._reads) and (not self._writes):
          return
        else:
          raise
      elif se.args[0] == EINTR:
        return
      elif se.args[0] == EBADF:
        self._preenDescriptors()
        return
      else:
        # OK, I really don't know what's going on. Blow up.
        raise

    _drdw = self._doReadOrWrite
    _logrun = log.callWithLogger
    for selectables, method, fdset in ((r, "doRead", self._reads),
                      (w,"doWrite", self._writes)):
      for selectable in selectables:
        # if this was disconnected in another thread, kill it.
        # ^^^^ --- what the !@#*? serious! -exarkun
        if selectable not in fdset:
          continue
        # This for pausing input when we're not ready for more.

        # 调用_doReadOrWrite方法
        _logrun(selectable, _drdw, selectable, method)

  doIteration = doSelect

  def _doReadOrWrite(self, selectable, method):
    try:
      # 调用method,doRead或者是doWrite,
      # 这里的selectable可能是我们监听的tcp.Port
      why = getattr(selectable, method)()
    except:
      why = sys.exc_info()[1]
      log.err()
    if why:
      self._disconnectSelectable(selectable, why, method=="doRead")

A continuación, el cliente si la solicitud de conexión, se llamará al método set tcp.Port doRead de la lectura.

# twisted/internet/tcp.py

@implementer(interfaces.IListeningPort)
class Port(base.BasePort, _SocketCloser):

  def doRead(self):
    """Called when my socket is ready for reading.
    当套接字准备好读的时候调用

    This accepts a connection and calls self.protocol() to handle the
    wire-level protocol.
    """
    try:
      if platformType == "posix":
        numAccepts = self.numberAccepts
      else:
        numAccepts = 1
      for i in range(numAccepts):
        if self.disconnecting:
          return
        try:
          # 调用accept
          skt, addr = self.socket.accept()
        except socket.error as e:
          if e.args[0] in (EWOULDBLOCK, EAGAIN):
            self.numberAccepts = i
            break
          elif e.args[0] == EPERM:
            continue
          elif e.args[0] in (EMFILE, ENOBUFS, ENFILE, ENOMEM, ECONNABORTED):
            log.msg("Could not accept new connection (%s)" % (
              errorcode[e.args[0]],))
            break
          raise

        fdesc._setCloseOnExec(skt.fileno())
        protocol = self.factory.buildProtocol(self._buildAddr(addr))
        if protocol is None:
          skt.close()
          continue
        s = self.sessionno
        self.sessionno = s+1
        # transport初始化的过程中,会将自身假如到reactor的读集合中,那么当它准备
        # 好读的时候,就可以调用它的doRead方法读取客户端发过来的数据了
        transport = self.transport(skt, protocol, addr, self, s, self.reactor)
        protocol.makeConnection(transport)
      else:
        self.numberAccepts = self.numberAccepts+20
    except:
      log.deferr()

método doRead, para recibir una llamada acepta la generación de socket de datos de cliente, transporte el zócalo y se unen, el transporte y después se añadió al reactor del conjunto de lectura. Cuando un cliente tiene datos llegan, se llamará método de transporte doRead para leer los datos.

La conexión es (instancia de transporte de la clase) Server de la clase padre, que implementa el método doRead.

# twisted/internet/tcp.py
@implementer(interfaces.ITCPTransport, interfaces.ISystemHandle)
class Connection(_TLSConnectionMixin, abstract.FileDescriptor, _SocketCloser,
         _AbortingMixin):

  def doRead(self):
    try:
      # 接收数据
      data = self.socket.recv(self.bufferSize)
    except socket.error as se:
      if se.args[0] == EWOULDBLOCK:
        return
      else:
        return main.CONNECTION_LOST

    return self._dataReceived(data)

  def _dataReceived(self, data):
    if not data:
      return main.CONNECTION_DONE
    # 调用我们自定义protocol的dataReceived方法处理数据
    rval = self.protocol.dataReceived(data)
    if rval is not None:
      offender = self.protocol.dataReceived
      warningFormat = (
        'Returning a value other than None from %(fqpn)s is '
        'deprecated since %(version)s.')
      warningString = deprecate.getDeprecationWarningString(
        offender, versions.Version('Twisted', 11, 0, 0),
        format=warningFormat)
      deprecate.warnAboutFunction(offender, warningString)
    return rval

_dataReceived llamar a un método de procesamiento de datos DataReceived ejemplo EchoProtocol de nuestra costumbre.

Me dirijo a usted, para todo el mundo para recomendar una muy amplia recolección de recursos de aprendizaje pitón, haga clic para entrar , hay un programador senior antes de aprender a compartir

Experiencia, señala el estudio, hay una posibilidad de experiencia en los negocios, y para todo el mundo para organizar cuidadosamente una pitón de combatir elemento de información basada cero,

Python día para que en la última tecnología, las perspectivas, el aprendizaje de los pequeños detalles que necesitan hacer comentarios sobre
este punto, un proceso sencillo, desde la creación hasta escuchar a los acontecimientos, a los datos de los clientes de recepción de este modo celebrados

Publicado 47 artículos originales · ganado elogios 34 · Vistas a 60000 +

Supongo que te gusta

Origin blog.csdn.net/haoxun08/article/details/104887218
Recomendado
Clasificación