Finger 的演变:一个 Twisted finger 客户端¶
简介¶
这是 Twisted 教程的第九部分 从零开始的 Twisted,或 Finger 的演变 。
在本部分中,我们将开发一个 finger 服务器的客户端:一个代理 finger 服务器,它将请求转发到另一个 finger 服务器。
Finger 代理¶
使用 Twisted 编写新的客户端与编写新的服务器非常相似。我们实现协议,它只收集所有数据并将其提供给工厂。工厂维护一个 Deferred,如果连接失败或成功,它将被触发。当我们使用客户端时,我们首先确保 Deferred 永远不会失败,方法是在这种情况下生成一条消息。实现一个围绕客户端的包装器,它只返回 Deferred,是一种常见的模式。虽然它不如直接使用工厂灵活,但它也更方便。
此外,由于这段代码现在以编程方式接收其主机和端口,因此使用 clientFromString 稍微有些不方便。相反,我们转向使用我们想要的特定端点。在本例中,由于我们正在使用 TCP 通过 IPv4 作为客户端进行连接,因此我们想要 TCP4ClientEndpoint
。
# finger proxy
from zope.interface import Interface, implementer
from twisted.application import internet, service, strports
from twisted.internet import defer, endpoints, protocol, reactor
from twisted.protocols import basic
from twisted.python import components
def catchError(err):
return "Internal error in server"
class IFingerService(Interface):
def getUser(user):
"""Return a deferred returning L{bytes}"""
def getUsers():
"""Return a deferred returning a L{list} of L{bytes}"""
class IFingerFactory(Interface):
def getUser(user):
"""Return a deferred returning L{bytes}"""
def buildProtocol(addr):
"""Return a protocol returning L{bytes}"""
class FingerProtocol(basic.LineReceiver):
def lineReceived(self, user):
d = self.factory.getUser(user)
d.addErrback(catchError)
def writeValue(value):
self.transport.write(value)
self.transport.loseConnection()
d.addCallback(writeValue)
@implementer(IFingerFactory)
class FingerFactoryFromService(protocol.ClientFactory):
protocol = FingerProtocol
def __init__(self, service):
self.service = service
def getUser(self, user):
return self.service.getUser(user)
components.registerAdapter(FingerFactoryFromService, IFingerService, IFingerFactory)
class FingerClient(protocol.Protocol):
def connectionMade(self):
self.transport.write(self.factory.user + b"\r\n")
self.buf = []
def dataReceived(self, data):
self.buf.append(data)
def connectionLost(self, reason):
self.factory.gotData("".join(self.buf))
class FingerClientFactory(protocol.ClientFactory):
protocol = FingerClient
def __init__(self, user):
self.user = user
self.d = defer.Deferred()
def clientConnectionFailed(self, _, reason):
self.d.errback(reason)
def gotData(self, data):
self.d.callback(data)
def finger(user, host, port=79):
f = FingerClientFactory(user)
endpoint = endpoints.TCP4ClientEndpoint(reactor, host, port)
endpoint.connect(f)
return f.d
@implementer(IFingerService)
class ProxyFingerService(service.Service):
def getUser(self, user):
try:
user, host = user.split("@", 1)
except BaseException:
user = user.strip()
host = "127.0.0.1"
ret = finger(user, host)
ret.addErrback(lambda _: "Could not connect to remote host")
return ret
def getUsers(self):
return defer.succeed([])
application = service.Application("finger", uid=1, gid=1)
f = ProxyFingerService()
strports.service("tcp:7779", IFingerFactory(f)).setServiceParent(
service.IServiceCollection(application)
)