使用Python的Twisted框架編寫簡單的網(wǎng)絡(luò)客戶端
Protocol
和服務(wù)器一樣,也是通過該類來實現(xiàn)。先看一個簡短的例程:
from twisted.internet.protocol import Protocol from sys import stdout class Echo(Protocol): def dataReceived(self, data): stdout.write(data)
在本程序中,只是簡單的將獲得的數(shù)據(jù)輸出到標(biāo)準(zhǔn)輸出中來顯示,還有很多其他的事件沒有作出任何響應(yīng),下面
有一個回應(yīng)其他事件的例子:
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()
本協(xié)議連接到服務(wù)器,發(fā)送了一個問候消息,然后關(guān)閉了連接。
connectionMade事件通常被用在建立連接的事件發(fā)生時觸發(fā)。關(guān)閉連接的時候會觸發(fā)connectionLost事件函數(shù)
(Simple, single-use clients)簡單的單用戶客戶端
在許多情況下,protocol僅僅是需要連接服務(wù)器一次,并且代碼僅僅是要獲得一個protocol連接的實例。在
這樣的情況下,twisted.internet.protocol.ClientCreator提供了一個恰當(dāng)?shù)腁PI
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)
ClientFactory(客戶工廠)
ClientFactory負(fù)責(zé)創(chuàng)建Protocol,并且返回相關(guān)事件的連接狀態(tài)。這樣就允許它去做像連接發(fā)生錯誤然后
重新連接的事情。這里有一個ClientFactory的簡單例子使用Echo協(xié)議并且打印當(dāng)前的連接狀態(tài)
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連接到服務(wù)器,可以使用下面代碼:
from twisted.internet import reactor reactor.connectTCP(host, port, EchoClientFactory()) reactor.run()
注意:clientConnectionFailed是在Connection不能被建立的時候調(diào)用,clientConnectionLost是在連接關(guān)閉的時候被調(diào)用,兩個是有區(qū)別的。
Reconnection(重新連接)
許多時候,客戶端連接可能由于網(wǎng)絡(luò)錯誤經(jīng)常被斷開。一個重新建立連接的方法是在連接斷開的時候調(diào)用
connector.connect()方法。
from twisted.internet.protocol import ClientFactory class EchoClientFactory(ClientFactory): def clientConnectionLost(self, connector, reason): connector.connect()
connector是connection和protocol之間的一個接口被作為第一個參數(shù)傳遞給clientConnectionLost,
factory能調(diào)用connector.connect()方法重新進(jìn)行連接
然而,許多程序在連接失敗和連接斷開進(jìn)行重新連接的時候使用ReconnectingClientFactory函數(shù)代替這個
函數(shù),并且不斷的嘗試重新連接。這里有一個Echo Protocol使用ReconnectingClientFactory的例子:
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)
A Higher-Level Example: ircLogBot
上面的所有例子都非常簡單,下面是一個比較復(fù)雜的例子來自于doc/examples目錄
# 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 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 made 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服務(wù)器,加入了一個頻道,并且在文件中記錄了所有的通信信息,這表明了在斷開連接進(jìn)行重新連接的連接級別的邏輯以及持久性數(shù)據(jù)是被存儲在Factory的。
Persistent Data in the Factory
由于Protocol在每次連接的時候重建,客戶端需要以某種方式來記錄數(shù)據(jù)以保證持久化。就好像日志機(jī)器人一樣他需要知道那個那個頻道正在登陸,登陸到什么地方去。
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
當(dāng)protocol被創(chuàng)建之后,factory會獲得他本身的一個實例的引用。然后,就能夠在factory中存在他的屬性。
更多的信息:
本文檔講述的Protocol類是IProtocol的子類,IProtocol方便的被應(yīng)用在大量的twisted應(yīng)用程序中。要學(xué)習(xí)完整的 IProtocol接口,請參考API文檔IProtocol.
在本文檔一些例子中使用的trasport屬性提供了ITCPTransport接口,要學(xué)習(xí)完整的接口,請參考API文檔ITCPTransport
接口類是指定對象有什么方法和屬性以及他們的表現(xiàn)形式的一種方法。參考 Components: Interfaces and Adapters文檔
- python如何通過twisted搭建socket服務(wù)
- Python3.6中Twisted模塊安裝的問題與解決
- python安裝twisted的問題解析
- python如何通過twisted實現(xiàn)數(shù)據(jù)庫異步插入
- python基于twisted框架編寫簡單聊天室
- python 編程之twisted詳解及簡單實例
- Python 基于Twisted框架的文件夾網(wǎng)絡(luò)傳輸源碼
- 剖析Python的Twisted框架的核心特性
- 實例解析Python的Twisted框架中Deferred對象的用法
- 詳解Python的Twisted框架中reactor事件管理器的用法
- 使用Python的Twisted框架編寫非阻塞程序的代碼示例
- Python的Twisted框架中使用Deferred對象來管理回調(diào)函數(shù)
- 使用Python的Twisted框架構(gòu)建非阻塞下載程序的實例教程
- Python的Twisted框架上手前所必須了解的異步編程思想
- 使用Python的Treq on Twisted來進(jìn)行HTTP壓力測試
- 利用Python的Twisted框架實現(xiàn)webshell密碼掃描器的教程
- 使用Python的Twisted框架實現(xiàn)一個簡單的服務(wù)器
- python開發(fā)實例之Python的Twisted框架中Deferred對象的詳細(xì)用法與實例
相關(guān)文章
使用虛擬環(huán)境打包python為exe 文件的方法
這篇文章主要介紹了關(guān)于使用虛擬環(huán)境打包python為exe 文件的方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2019-08-08pandas object格式轉(zhuǎn)float64格式的方法
下面小編就為大家分享一篇pandas object格式轉(zhuǎn)float64格式的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-04-04python 實現(xiàn)12bit灰度圖像映射到8bit顯示的方法
這篇文章主要介紹了python 實現(xiàn)12bit灰度圖像映射到8bit顯示的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07利用Python+阿里云實現(xiàn)DDNS動態(tài)域名解析的方法
這篇文章主要介紹了利用Python+阿里云實現(xiàn)DDNS動態(tài)域名解析的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-04-04在Python的Django框架中simple-todo工具的簡單使用
這篇文章主要介紹了在Python的Django框架中simple-todo工具的簡單使用,該工具基于原web.py中的開源項目,需要的朋友可以參考下2015-05-052023年最新版Python?3.12.0安裝使用指南(推薦!)
這篇文章主要給大家介紹了關(guān)于2023年最新版Python?3.12.0安裝使用的相關(guān)資料,Python?現(xiàn)在是非常流行的編程語言,當(dāng)然并不是說Python語言性能多么強(qiáng)大,而是Python使用非常方便,特別是現(xiàn)在AI和大數(shù)據(jù)非常流行,用?Python?實現(xiàn)是非常容易的,需要的朋友可以參考下2023-10-10