2.Twisted学习
2018-12-06 07:35:30来源:博客园 阅读 ()
编写一个客户端
概论
Twisted是一个设计十分灵活的框架,而且允许编写出非常强大的客户端。编写灵活的客户端的只需要你写几个层就可以了。这个文档涵盖了如何创建一个客户端,不包括UDP UDP is covered in a different document .
首先,Protocol类是你通常用来执行和解析协议的地方。这个类每次都twisted.internet.protocol.Protocol
许多协议的执行继承这个类或者它的子类。一个protocol类会被实例化每当你链接服务器的时候,而且在离开的时候会断开连接。这就是说,持久性的配置不会保存在Protool里。
持久化的类被保存在Factory里边。它继承自twisted.internet.protocol.Factory (or twisted.internet.protocol.ClientFactory
默认的工厂累只会实例化Protocol只后设置协议的factory属性来指向这个协议。
这是例子:
这个简单的例子只会进行回显。
再来个例子:
看过我翻译的第一章的读者应该很熟悉这两个例子了,就是连接之后就回复,之后关闭。
好吧,开始进入正题,编写一个客户端
在许多例子里,protocol仅仅需要连接服务器一次就可以了,而且代码只想要获得链接协议的第一个实例对象,在这些例子里边,twisted.internet.endpoints提供了合适的API接口,connectProtocol 用的是protocol的实例,而不是工厂的实例!
不管客户端的类型是什么,建立新的连接的方法只是把它通过 connectProtocol和协议实例。这也就是说非常容易改变你链接的状态,不用修改其他部分。举个例子,为了运行C例子(用SSL),只需要实例化 SSL4ClientEndpoint 代替 TCP4ClientEndpoint,为了使用这个优点,发起新的连接的函数和方法通常应该把endpoint作为参数,之后让调用者创建它,而不是使用‘host’和‘port’之类的参数来构建自己的端点。
你可能会看到用以下的代码创建一个客户端,这比较古老了:
1 from twisted.internet.protocol import ClientCreator 2 3 ... 4 5 creator = ClientCreator(reactor, Greeter) 6 d = creator.connectTCP("localhost", 1234) 7 d.addCallback(gotProtocol) 8 reactor.run()
客户端工厂
现在依然有许多底层的API在外边,一些特性(比如自动重新连接)还没有用endpoint实现,所以在某些情况下使用它们可能会比较方便。
如果要使用底层api,需要调用reactor.connect。为了实现这些例子,你需要 ClientFactory。这个工厂是负责创建Protocol而且会接受和连接状态有关的事件。它允许你做一些事情,比如在一个连接错误之后再次连接。
给个例子:
把它连接到一个服务器,你先需要写一些code:
服务器启动一下,会显示如下:
客户端reactor的api
connectTCP
IReactorTCP.connectTCP提供了IPV4,IPV6的tcp客户端方法。
参数有:host接受地址或者主机名,如果是主机名的话,reactor会自定解析为IP地址(多余开销)
port接受端口
Reconnection
我们通常都会遇到连接失败的请跨国。一个重新连接的方法:
第一个作为参数被传递的reactor是连接和协议之间的接口。当连接失败的时候,工厂会调用lost方法,之后调用connect()重新连接。
但是,大多数想要实现这个方法的工厂都应该重写ReconnectingClientFactory,而不是像上边那样,这个被重写的方法会尝试连接如果连接lost挥着faild,而且会自动实现梯度延迟。
给你个例子:
高级例子:
这个客户端到目前为止还十分简单。一个更加复杂的例子来了:
# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ An example IRC log bot - logs a channel's events to a file. If someone says the bot's name in the channel followed by a ':', e.g. <foo> logbot: hello! the bot will reply: <logbot> foo: I am a log bot Run this script with two arguments, the channel name the bot should connect to, and file to log to, e.g.: $ python ircLogBot.py test test.log will log channel #test to the file 'test.log'. To run the script: $ python ircLogBot.py <channel> <file> """ from __future__ import print_function # twisted imports from twisted.words.protocols import irc from twisted.internet import reactor, protocol from twisted.python import log # system imports 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 successfully 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)) # For fun, override the method that determines how a nickname is changed on # collisions. The default method appends an underscore. def alterCollidedNick(self, nickname): """ Generate an altered version of a nickname that caused a collision in an effort to create an unused related name for subsequent registration. """ return nickname + '^' class LogBotFactory(protocol.ClientFactory): """A factory for LogBots. A new protocol instance will be created each time we connect to the server. """ def __init__(self, channel, filename): self.channel = channel self.filename = filename def buildProtocol(self, addr): p = LogBot() p.factory = self return p 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()
工厂中的持久数据
因为每次protocol连接都会创建一个实例,客户端需要以某种方式来跟踪持久化的数据。在日志的记录下,需要知道他正在记录哪一个通道,,以及在哪里对他进行日志记录。
1 from twisted.words.protocols import irc 2 from twisted.internet import protocol 3 4 class LogBot(irc.IRCClient): 5 6 def connectionMade(self): 7 irc.IRCClient.connectionMade(self) 8 self.logger = MessageLogger(open(self.factory.filename, "a")) 9 self.logger.log("[connected at %s]" % 10 time.asctime(time.localtime(time.time()))) 11 12 def signedOn(self): 13 self.join(self.factory.channel) 14 15 16 class LogBotFactory(protocol.ClientFactory): 17 18 def __init__(self, channel, filename): 19 self.channel = channel 20 self.filename = filename
创建协议的时候,它会获得一个工厂的引用,self.factory,它可以在之后访问工厂的属性,比如Logbot,
它打开文件并且连接到工厂中的channel
Factories有一个默认的方法BuildProtocol,它使用protoccol实例来创建。
1 class LogBotFactory(protocol.ClientFactory): 2 protocol = LogBot 3 4 def __init__(self, channel, filename): 5 self.channel = channel 6 self.filename = filename
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:python装饰器详解
- Python学习日记(十) 生成器和迭代器 2019-08-13
- python学习-53 正则表达式 2019-08-13
- python爬虫学习之爬取超清唯美壁纸 2019-08-13
- python爬虫学习之用Python抢火车票的简单小程序 2019-08-13
- Python学习日记(九) 装饰器函数 2019-08-13
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash