? ? ? ? 最近假期在家跟着《Python核心编程》学习这门语言,在网络编程这一章中书上提到了Twisted框架,但介绍寥寥。于是打算跟着函数过一遍流程,但完整流程对一个初学者来说过于复杂,于是退而求其次尝试理解其中的NIO架构,以下内容为个人理解,如有错误,还烦请不吝赐教。
? ? ? ? 从书上给的服务端代码开始:
from twisted.internet import protocol,reactor
PORT=17025
class tspro(protocol.Protocol):
def connectionMade(self):
clnt=self.clnt=self.transport.getPeer()
print('connected from:',clnt)
def dataReceived(self, data):
self.transport.write(data)
factory=protocol.Factory()
factory.protocol=tspro
print('waiting for connection')
reactor.listenTCP(PORT,factory)
reactor.run()
? ? ? ? 可以看到从twisted中引入了两个模块:factory与reactor。factory作为创建实例的工厂先不深究,重点在于最后的reactor.listen()与reactor.run()。直接点进reactor发现代码如下:
import sys
del sys.modules["twisted.internet.reactor"]
from twisted.internet import default
default.install()
? ? ? ? ?里面调用了default.install()函数,继续查看:
try:
if platform.isLinux():
try:
from twisted.internet.epollreactor import install
except ImportError:
from twisted.internet.pollreactor import install
elif platform.getType() == "posix" and not platform.isMacOSX():
from twisted.internet.pollreactor import install
else:
from twisted.internet.selectreactor import install
except ImportError:
from twisted.internet.selectreactor import install
return install
? ? ? ? 跨平台适配,查看针对Linux系统创建epollreactor类的代码
def install():
"""
Install the epoll() reactor.
"""
p = EPollReactor()
from twisted.internet.main import installReactor
installReactor(p)
def __init__(self):
"""
Initialize epoll object, file descriptor tracking dictionaries, and the
base class.
"""
# Create the poller we're going to use. The 1024 here is just a hint
# to the kernel, it is not a hard maximum. After Linux 2.6.8, the size
# argument is completely ignored.
self._poller = epoll(1024)
self._reads = set()
self._writes = set()
self._selectables = {}
self._continuousPolling = posixbase._ContinuousPolling(self)
posixbase.PosixReactorBase.__init__(self)
def _add(self, xer, primary, other, selectables, event, antievent):
"""
Private method for adding a descriptor from the event loop.
It takes care of adding it if new or modifying it if already added
for another state (read -> read/write for example).
"""
fd = xer.fileno()
if fd not in primary:
flags = event
# epoll_ctl can raise all kinds of IOErrors, and every one
# indicates a bug either in the reactor or application-code.
# Let them all through so someone sees a traceback and fixes
# something. We'll do the same thing for every other call to
# this method in this file.
if fd in other:
flags |= antievent
self._poller.modify(fd, flags)
else:
self._poller.register(fd, flags)
# Update our own tracking state *only* after the epoll call has
# succeeded. Otherwise we may get out of sync.
primary.add(fd)
selectables[fd] = xer
? ? ? ? 在这里驱动本次reactor的事件的句柄被提取放入self._reads或self._writes组成事件表,配合reactor.run()循环中调用seletreactor建立readylist,通过遍历readylist针对不同类型的读、写或连接建立事件调用自己定义的protocol.connectionMade()或protocol.dataReceive()等方法进行并发处理。
|