原文:http://www.klipdas.com/blog/?p=twisted-clients
客户端
2.2.1 概述.
Twisted框架设计的很灵活,可以编写功能强大的客户端。灵活的代价在于编写客户端方法的多一些层次,文档涵盖了使用TCP,SSL和Unix sockets,UDP来创建客户端,它们分别都有介绍(92页)。
基本上,实际实现协议的解析和处理的是在Protocol类中。该类通常继承至twisted.internet.protocol.Protocol,大多数协议处理程序要么继承至该类,要么是其子类。当你连接到服务器时协议类就会实例化一个实体,在你离开的时候,被释放。就是说持久的配置不会驻留在Protocol中。
持久配置被保存在Factory类中,它通常继承至twisted.internet.protocol.ClientFactory。默认的工厂类只实例化Protocol,并赋值给它的factory属性,这就允许Protocol访问,有可能修改持久化配置。
2.2.2 协议
如上所述,协议、辅助类和函数是大部分代码。Twisted协议以异步形式处理数据,就是说协议从不等待事件,而是在收到事件时回复。 示例:
from twisted.internet.protocol import Protocol from sys import stdout class Echo(Protocol): def dataReceived(self, data): stdout.write(data)
这是一个最简单的协议,只是简单的将接收到的数据写入标准输出中去,还有很多的事件它没有响应。下面时候Protocol响应其他事情的示例:
from twisted.internet.protocol import Protocol class WelcomeMessage(Protocol): def connectionMade(self): self.transport.write("Hello server, I am the client!\r\n") self.transport.loseConnection()
该协议连接到服务器,发送一条欢迎消息,然后终止连接。
connectionMade事件通常发生在Protocol对象设置的地方,同时初始化问候语(就像上面的WelcomeMessage协议)。特定的Protocol对象会在connectionLost事件中被清除。
2.2.3 简易单用户客户端
很多情况下,协议只需要连接服务器一次,程序只想获取一个协议连接的实例。这些情况下,twisted.internet.protocol.ClientCreator提供了必要的API。
from twisted.internet import reactor from twisted.internet.protocol import Protocol, ClientCreator class Greeter(Protocol): def sendMessage(self, msg): self.transport.write("MESSAGE %s\n" % msg) def gotProtocol(p): p.sendMessage("Hello") reactor.callLater(1, p.sendMessage, "This is sent in a second") reactor.callLater(2, p.transport.loseConnection) c = ClientCreator(reactor, Greeter) c.connectTCP("localhost", 1234).addCallback(gotProtocol)
2.2.4 ClientFactory
我们使用reactor.connect*和ClientFactory,该ClientFactory负责创建Protocol,并接收与连接状态相关的事件,它可以做一些工作,如在连接错误事件中进行重新连接。下面是一个简单ClientFactory的示例,它使用Echo协议(见上述)并打印出连接状态。
from twisted.internet.protocol import Protocol, ClientFactory from sys import stdout class Echo(Protocol): def dataReceived(self, data): stdout.write(data) class EchoClientFactory(ClientFactory): def startedConnecting(self, connector): print 'Started to connect.' def buildProtocol(self, addr): print 'Connected.' return Echo() def clientConnectionLost(self, connector, reason): print 'Lost connection, Reason:', reason def clientConnectionFailed(self, connector, reason): print 'Connection failed. Reason:', reason
为使EchoClientFactory连接服务器,添加如下代码:
from twisted.internet import reactor reactor.connectTCP(host, port, EchoClientFactory()) reactor.run()
注意:clientConnectionFailed在不能建立连接时被调用,clientConnectionLost在创建连接后被释放时调用。
重新连接
很多时候,由于网络错误,客户端连接就会丢失意义。有一种方法,在连接中断时,disconnection会调用connector.connect()来重新进行连接:
from twisted.internet.protocol import ClientFactory class EchoClientFactory(ClientFactory): def clientConnectionLost(self, connector, reason): connector.connect()
作为第一个参数传递的connector是connection和protocol的接口,当连接失败,factory收到clientConnectionLost事件时,factory可以调用connector.connect()来从头开始建立连接。
然而,大部分需要这个功能的程序应该是实现ReconnectingClientFactory,它在连接中断或失败时尝试重新连接,不断的延时并不断尝试重新连接。
下面是实现了ReconnectingClientFactory的Echo协议:
from twisted.internet.protocol import Protocol, ReconnectingClientFactory from sys import stdout class Echo(Protocol): def dataReceived(self, data): stdout.write(data) class EchoClientFactory(ReconnectingClientFactory): def startedConnecting(self, connector): print 'Started to connect.' def buildProtocol(self, addr): print 'Connected.' print 'Resetting reconnection delay' self.resetDelay() return Echo() def clientConnectionLost(self, connector, reason): print 'Lost connection. Reason:', reason ReconnectingClientFactory.clientConnectionLost(self, connector, reason) def clientConnectionFailed(self, connector, reason): print 'Connection failed. Reason:', reason ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)
2.2.5 高级示例: ircLogBot
ircLogBot简介
到现在的客户端还相当简单,更复杂的示例在Twisted文档的doc/examples目录下面。
from twisted.words.protocols import irc from twisted.internet import reactor, protocol from twisted.python import log import time, sys class MessageLogger: """ An independent logger class (because separation of application and protocol logic is a good thing). """ def __init__(self, file): self.file = file def log(self, message): """Write a message to the file.""" timestamp = time.strftime("[%H:%M:%S]", time.localtime(time.time())) self.file.write('%s %s\n' % (timestamp, message)) self.file.flush() def close(self): self.file.close(); class LogBot(irc.IRCClient): """A logging IRC bot.""" nickname = "twistedbot" def connectionMade(self): irc.IRCClient.connectionMade(self) self.logger = MessageLogger(open(self.factory.filename, "a")) self.logger.log("[connected at %s]" %time.asctime(time.localtime(time.time()))) def connectionLost(self, reason): irc.IRCClient.connectionLost(self, reason) self.logger.log("[disconnected at %s]" % time.asctime(time.localtime(time.time()))) self.logger.close() #callbacks for events def signedOn(self): """Called when bot has succesfully signed on to server.""" self.join(self.factory.channel) def joined(self, channel): """This will get called when the bot joins the channel.""" self.logger.log("[I have joined %s]" % channel) def privmsg(self, user, channel, msg): """This will get called when the bot receives a message.""" user = user.split('!', 1)[0] self.logger.log("<%s> %s" % (user, msg)) #Check to see if they're sending me a private message if channel == self.nickname: msg = "It isn't nice to whisper! Play nice with the group." self.msg(user, msg) return #Otherwise check to see if it is a message directed at me if msg.startswith(self.nickname + ":"): msg = "%s: I am a log bot" % user self.msg(channel, msg) self.logger.log("<%s> %s" % (self.nickname, msg)) def action(self, user, channel, msg): """This will get called when the bot sees someone do an action.""" user = user.split('!', 1)[0] self.logger.log("* %s %s" % (user, msg)) #irc callbacks def irc_NICK(self, prefix, params): """Called when an IRC user changes their nickname.""" old_nick = prefix.split('!')[0] new_nick = params[0] self.logger.log("%s is now known as %s" % (old_nick, new_nick)) class LogBotFactory(protocol.ClientFactory): """A factory for LogBots A new protocol instance will be created each time we connect to the server. """ #the class of the protocol to build when new connection is mede protocol = LogBot def __init__(self, channel, filename): self.channel = channel self.filename = filename def clientConnectionLost(self, connector, reason): """If we get disconnected, reconnect to server.""" connector.connect() def clientConnectionFailed(self, connector, reason): print "connection failed:", reason reactor.stop() if __name__ == '__main__': #initialize logging log.startLogging(sys.stdout) #create factory protocol and application f = LogBotFactory(sys.argv[1], sys.argv[2]) #connect factory to this host and port reactor.connectTCP("irc.freenode.net", 6667, f) #run bot reactor.run()
ircLogBot.py连接IRC服务器,调入一个频道并将所以流量记录到文件中,它表明了连接中断时重新连接的连接层逻辑,以及Factory中的持久数据。
Factory中的持久数据
由于Protocol实例在每次连接时都会重新创建,客户端需要一些方法来跟踪应该被持久化的数据。在这个logging bot案例中,它需要知道哪个频道被记录及记录在哪里。
from twisted.internet import protocol from twisted.protocols import irc class LogBot(irc.IRCClient): def connectionMade(self): irc.IRCClient.connectionMade(self) self.logger = MessageLogger(open(self.factory.filename, "a")) self.logger.log("[connected at %s]" %time.asctime(time.localtime(time.time()))) def signedOn(self): self.join(self.factory.channel) class LogBotFactory(protocol.ClientFactory): protocol = LogBot def __init__(self, channel, filename): self.channel = channel self.filename = filename
当protocol被创建,它就会得到factory的引用赋值给self.factory,它可以通过自身的逻辑对factory的属性进行访问。在LogBot案例中,它打开文件,并连接factory中的通道存储。
2.2.6 延伸
本书中所使用的Protocol类是实现了IProtocol接口的基本类,该接口在大多少Twisted应用都广泛应用。要了解完整的IProtocol接口,请参阅API文档。
本书中在一些示例中使用的transport属性提供了ITCPTransport接口,要了解有关该接口的详细情况,参阅ITCPTransport的API文档。
接口是用于指定一个类所拥有的或如何使用的方法和属性的。参阅Components:Interfaces和Adapters(文档148页)。
相关推荐
Python-txRedis是针对Twisted框架的一个高效、异步的Redis客户端库,它允许你在Twisted事件循环中无缝地操作Redis服务器。这个库是为了解决在非阻塞环境中进行数据库交互的需求,使得你的Python应用在处理大量并发...
### Twisted入门教程知识点梳理 #### 一、Twisted理论基础 - **异步编程模型简介**:异步编程是一种编程范式,其中程序的控制流不会被阻塞等待某个操作完成,而是允许其他任务继续执行。这在处理I/O密集型任务(如...
本系列教程是对Twisted框架的详细介绍,从基础理论到实际应用,逐步引导读者入门并深入理解Twisted的各种用法。 在第一部分,教程首先介绍了Twisted理论基础,强调了异步编程的重要性以及reactor模式。异步编程模型...
本教程深入介绍了Twisted的理论基础、异步编程模式与Reactor的初探、Twisted支持的客户端与服务器的开发以及Deferred对象的使用。Deferred是Twisted框架中用于处理异步操作完成后的回调函数的对象,它能够帮助开发者...
本教程将深入探讨 Twisted 的基础知识和主要组件。 ### 1. Twisted 的核心概念 - **事件驱动编程**: Twisted 使用非阻塞I/O模型,基于事件循环,当数据就绪时触发回调函数,而非等待I/O操作完成。这使得程序在等待...
### Twisted系列教程知识点概述 #### 第一部分:Twisted理论基础 - **前言**:这一部分主要介绍了Twisted框架的背景以及对于那些寻求快速入门的读者来说,Twisted可能并非是一个简单易学的选择。作者指出,对于希望...
2. **TCP服务**:可能会有一个简单的TCP服务器示例,展示如何使用Twisted来监听和处理客户端的TCP连接。这将涉及`twisted.internet.protocol`和`twisted.internet.endpoints`模块。 3. **UDP通信**:除了TCP,...
Twisted 是一个用 Python 编写的事件驱动网络引擎,适用于服务器端和客户端应用程序。它支持多种协议,包括但不限于 TCP、UDP、SSL/TLS、HTTP 和 IRC。Twisted 的设计理念强调了模块化和可扩展性,使得开发人员能够...
在本文档的开头,作者指出对于那些希望快速了解Twisted的人来说,本教程可能并不是最佳选择,因为真正理解和掌握Twisted及异步编程需要一定的时间和基础。 #### Twisted理论基础 在正式进入Twisted之前,文档首先...
### Python Twisted 网络编程教程:深入解析与代码示例 #### 一、引言及 Twisted 概览 ##### 1.1 Twisted 的愿景 Twisted 是一个用 Python 编写的事件驱动网络引擎,其核心设计旨在简化异步编程。Twisted 的愿景是...
- **第2章 教程**:提供编写服务器与客户端的具体示例,并逐步深入到高级应用场景。 **重要知识点解析:** 1. **扭曲框架的愿景**:构建一个强大且灵活的异步网络框架,支持多种网络协议和服务。 2. **扭曲框架的...
“python2.5andtwisted”这个文件可能是一个包含教程或示例代码的文档,展示了如何在Python 2.5环境下安装和使用Twisted框架。学习这个文档将有助于理解如何在旧版本的Python环境中配置和运行Twisted项目。 在实际...
标签中的“文档”则表明给定的文件是一份文档资料,它可能是Twisted框架的官方入门指南、教程或其他形式的文档。 部分内容描述了文档的结构和内容,开始于对异步编程和Twisted框架的简单介绍。文档提到,快速入门...
这个压缩包包含的文件名为"twistedTUTXX - Woodpecker Wiki for CPUG.mht",其中XX可能是01到11的数字,这些文件很可能是Woodpecker Wiki为计算机用户组(CPUG)编写的关于Twisted框架的教学教程。 Twisted的核心是它...