파이썬 기준 : 파이썬 트위스트 프레임 워크 반응기 이벤트 관리자의 상세 사용

이 문서는 파이썬의 트위스트 프레임 워크의 반응 자세한 사용법의 이벤트 매니저, 트위스트 비동기 파이썬 개발 프레임 워크 높은 인기를 참조에서 필요 캔의 친구입니다 설명
침구
연습을 많이에서, 우리가 비슷한 항상 것 같다 방법은 비동기 프로그래밍을 사용합니다 :

모니터 이벤트
이벤트는 해당 콜백 함수의 실행
콜백 (청취 큐에 추가 가능한 새로운 이벤트) 완료
, 이벤트를 수신 한에 다시
, 우리는이 비동기 모드는 원자로 패턴이라고 있도록 iOS의 개발에 실행 루프 개념으로, 사실상, 반응기 루프와 매우 유사하게, 실행 루프 메인 쓰레드 모니터 화면 UI 이벤트 실행되는 이벤트에 대응하는 처리 코드 UI 이벤트 후에, 다른 수단 GCD에 의해 메인 스레드 실행에 이벤트를 생성 할 수있다. 그림 삽입 설명 여기
이벤트를 처리하는 이벤트를 기다리는 동안 그림은 원자로 부스트 모드의 묘사이다, 트위스트 디자인이 원자로 패턴을 기반으로, 트위스트 프로그램이 연속 루프입니다.

from twisted.internet import reactor
reactor.run()

트위스트 반응기는 단일의 오브젝트 프로그램이다.

리액터
반응기 이벤트 루프를 실행하는 등록 이벤트 매니저는 이벤트 취소이며, 이벤트가 발생했을 때 처리하는 콜백 함수를 호출한다. 원자로 다음에 대한 몇 가지 결론이 있습니다 :

트위스트의 반응은 reactor.run를 호출하여 시작 ().
루프 반응기는 주 공정에서의 프로세스 실행의 시작 부분에서 실행된다.
시작되면, 그것은 영원히 실행됩니다. 반응기 (그 스레드의 프로모터의 제어하에 또는 특히) 프로그램의 제어하에있을 것이다.
원자로주기 및 CPU 리소스를 소모하지 않습니다.
당신은 명시 적으로 반응, 단지 확인을 도입를 만들 필요가 없습니다.
마지막으로, 필요가 설명합니다. 트위스트에서 반응이 반응기 내에서 하나 개의 프로그램입니다, 그리고 당신이 그것을 소개로 따라 하나를 만들 것을, 싱글 (즉, 싱글 톤)입니다. 본 실시 예는 상기 기본 꼬임을 도입하는 방법은 물론, 다른 방법으로는, 반응기가 도입 될 수 꼬여있다. 예를 들어, 대신 여론 조사 전화는 방법 twisted.internet.pollreactor 시스템을 선택합니다.

다른 원자로를 사용하려면, 그것은 소개 twisted.internet.reactor하기 전에 설치해야합니다. 다음은 설치 pollreactor하는 방법입니다 :

from twisted.internet import pollreactor
pollreactor.install()

특수 원자로 도입 twisted.internet.reactor 기타를 설치할 필요가 없습니다 경우, 트위스트은 기본 리액터를 설치하여 운영 체제를 기반으로합니다. 이것 때문에 관행은 기본 반응기를 설치하지 않도록 최상위 모듈 원자로를 도입하지,하지만 당신은 원자로를 사용하고자하는 지역에 설치되어있다.
다음 절차 위의 재기록 pollreactor입니다 :

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

그런 다음 반응은 하나의 사건을 달성하는 방법은? twisted.internet 가져 오기 반응기에서 봐 무슨 일을하고 이해합니다.

다음은 / 인터넷 / reactor.py의 꼬인 코드의 일부이다 :

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

참고 : 파이썬 모든 메모리 모듈에로드는 글로벌 사전입니다 sys.modules에 배치됩니다. 먼저 부하가 단순히 수입 모듈 네임 스페이스를 호출하는 모듈의 이름에 추가 된 경우 목록에서 모듈이 이미이 모듈을로드 할 때 가져 볼 것이다. 모듈 파일에 의해 모듈의 이름을 찾기 위해 sys.path에 디렉토리에서로드하지 않으면 모듈이 메모리에로드하고 sys.modules에 추가됩니다 발견하고 현재 네임 스페이스에 이름을 입력합니다.

sys.modules에이 twisted.internet.reactor되지 않았기 때문에 우리가 먼저 twisted.internet 가져 오기 반응기에서 실행되는 경우, 코드 reactory.py를 실행하는 기본 반응기를 설치합니다. 모듈의 sys.modules에 이미 존재하기 때문에 당신이 그것을 가져 오면 그 후, 그것은 바로 현재의 이름 공간에 twisted.internet.reactor에 sys.modules에 있습니다.

기본 설치 :

注: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:

물론, 기본적으로 해당 플랫폼에 따라 설치 얻을 것이다. 리눅스에서 커널이 지원하지 않는 경우, 당신은 단지 pollreactor를 사용할 수 epollreactor을 먼저 사용됩니다. 맥 플랫폼 pollreactor는 창 selectreactor를 사용합니다. 우리가보고 설치 selectreactor를 추출 할 경우 각각의 설치는 거의 얻을 수있다.

# 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

installReactor가 sys.modules에 twisted.internet.reactor 키에 추가에서는 단일 반응기 값을 생성하고 설치한다. 이후 반응기를 사용할 수 있도록, 이는 하나의 실시 예에 도입한다.

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

구현 표현 SelectReactor 구현 방법 IReactorFDSet 인터페이스는 파이썬 인터페이스가, 관심있는 학생들은 다음에 갈 수있다, 여기 zope.interface을 사용했다.
IReactorFDSet 주로 수집 설명, 추가 또는 작업의 삭제 방법을 인터페이스. 내가 코멘트를 추가하지 않은 때문에 이러한 방법은, 의미를 알고 이름을 볼 수 있습니다.

# 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()

reactor.listenTCP의 예는 ()는 상위 클래스 PosixReactorBase 방법이며, 이벤트 리스너를 등록했다.

# 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()

듣기, 전체 논리는 간단하고, 정상으로 서버 측 소켓을 생성, 바인드. 반응기의 읽기 세트에 추가하는 소켓 기술자를 제외합니다. 단어를 통해 클라이언트와의 연결이 원자로가 모니터링 할 경우 그래서, 이벤트 핸들러가 트리거됩니다.

reacotr.run () 메인 이벤트 루프

# 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는 메인 루프는 읽기 및 쓰기하는 기술자의 집합을 모니터링, 전화 doIteration 방법 재활용에 최고입니다, 읽기 및 쓰기 준비, 이벤트 핸들러를 호출합니다.

# 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")

그런 다음 클라이언트가 연결 요청하는 경우, 그것은 독서의 세트 tcp.Port doRead 메소드를 호출합니다.

# 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()

doRead 방법은, 통화가 클라이언트 데이터를 생성 소켓 수용 수용 소켓 인드 수송을 수송하고 판독 한 세트의 반응기에 첨가 하였다. 클라이언트가 도착하는 데이터가있는 경우 데이터를 읽기 위해, 그것은 doRead 전송 방법을 호출합니다.

연결 방법을 구현 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 예제 EchoProtocol 처리 방법을 호출 _dataReceived.

나는 모두가 매우 넓은 파이썬 학습 자원 수집을 권장하기 위해, 당신에 기록 입력을 클릭 , 공유 학습 전 수석 프로그래머가있다

체험, 연구 노트, 사업 경험의 기회가, 모든 사람들이주의 깊게 전투에 파이썬을 구성하는 정보의 항목을 0부터

최신 기술에 당신에게 파이썬 날, 전망, 작은 세부 사항을 학습에 대해 언급 할 필요가
생성에서이 점, 간단한 프로세스, 따라서 결론을 내렸다 수신 클라이언트 데이터, 이벤트를 수신하기

게시 47 개 원래 기사 · 원의 찬양 (34) ·은 60000 +를 볼

추천

출처blog.csdn.net/haoxun08/article/details/104887218