玩轉Twisted之一:介紹

Python編寫的事件驅動的網絡引擎

  • twisted.web: HTTP 客戶端和服務器, HTML 模板, 和一個 WSGI 服務器
  • twisted.conch: SSHv2 和 Telnet 客戶端和服務器,以及一個終端模擬器
  • twisted.words: IRC, XMPP客戶端和服務器, 以及其他 IM(Instant Message) 協議
  • twisted.mail: IMAPv4, POP3, SMTP 客戶端和服務器
  • twisted.positioning: 和NMEA兼容的 GPS 接受者通信的工具
  • twisted.names: DNS 客戶端 和構建自己DNS服務器的工具
  • twisted.trial: 單元測試框架

Twisted 支持所有主流操作系統的時間循環 -- select (所有平臺), poll (大多數 POSIX 平臺), epoll (Linux), kqueue (FreeBSD, macOS), IOCP (Windows), 和多種GUI事件循環 (GTK+2/3, Qt, wxWidgets). 第三方reactors 可以插入 Twisted,並提供多種其他事件循環。

安裝

pip install twisted

安裝支持tls的版本

pip instal twisted[tls]

示例代碼

Echo 服務器

Twisted使實現定製網絡應用變得簡單。下面是一個TCP服務器,響應回覆發給它的所有文本:

from twisted.internet import protocol, reactor, endpoints

class Echo(protocol.Protocol):
    def dataReceived(self, data):
        data = "Echo-Server:".encode()+data
        self.transport.write(data)


class EchoFactory(protocol.Factory):
    def buildProtocol(self, addr):
        return Echo()
endpoints.serverFromString(reactor, "tcp:1234").listen(EchoFactory())
reactor.run()

使用netcat進行測試:

$netcat -v 127.0.0.1 1234

Connection to 127.0.0.1 1234 port [tcp/*] succeeded!
你好
Echo-Server:你好
中華人民共和國
Echo-Server:中華人民共和國

Web 服務器

Twisted 包含一個事件驅動web服務器. 下面是一個Web應用樣例; 注意資源對象如何持久化到內存,而不是每次請求都重新創建

from twisted.web import server, resource
from twisted.internet import reactor, endpoints


class Counter(resource.Resource):
    isLeaf = True
    numberRequests = 0

    def render_GET(self, request):
        self.numberRequests += 1
        request.setHeader(b"content-type", b"text/plain")
        content = u"我是請求 #{}\n".format(self.numberRequests)
        return content.encode("utf-8")


endpoints.serverFromString(reactor, "tcp:8080").listen(server.Site(Counter()))
reactor.run()

使用curl進行測試

$ curl 127.0.0.1:8080
我是請求 #1
$ curl 127.0.0.1:8080
我是請求 #2
$ curl 127.0.0.1:8080
我是請求 #3

發佈/訂閱 服務器

下面是一個簡單的publish/subscribe 服務器, 客戶端可以看到其他客戶端發送的所有信息

from twisted.internet import reactor, protocol, endpoints
from twisted.protocols import basic


class PubProtocol(basic.LineReceiver):
    def __init__(self, factory):
        self.factory = factory

    def connectionMade(self):
        self.factory.clients.add(self)

    def connectionLost(self, reason):
        self.factory.clients.remove(self)

    def lineReceived(self, line):
        for c in self.factory.clients:
            source = u"<{}> ".format(self.transport.getHost()).encode("utf-8")
            c.sendLine(source + line)


class PubFactory(protocol.Factory):
    def __init__(self):
        self.clients = set()

    def buildProtocol(self, addr):
        return PubProtocol(self)


endpoints.serverFromString(reactor, "tcp:1025").listen(PubFactory())
reactor.run()

開啓兩個終端,使用telnet進行測試:
客戶端1:

telnet 127.0.0.1 1025
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
今天天氣不錯,我是客戶端#1
<IPv4Address(type='TCP', host='127.0.0.1', port=1025)> 今天天氣不錯,我是客戶端#1
<IPv4Address(type='TCP', host='127.0.0.1', port=1025)> 是啊是啊!是客戶端#2

客戶端#2

telnet 127.0.0.1 1025
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
<IPv4Address(type='TCP', host='127.0.0.1', port=1025)> 今天天氣不錯,我是客戶端#1
是啊是啊!我是客戶端#2
<IPv4Address(type='TCP', host='127.0.0.1', port=1025)> 是啊是啊!是客戶端#2

郵件客戶端

Twisted 包含一個高明的(sophisticated) IMAP4 客戶端庫.


import sys

from twisted.internet import protocol, defer, endpoints, task
from twisted.mail import imap4
from twisted.python import failure


async def main(
    reactor, username="TaceyWong", password="secret", strport="tls:example.com:993"
):
    endpoint = endpoints.clientFromString(reactor, strport)
    factory = protocol.Factory.forProtocol(imap4.IMAP4Client)
    try:
        client = await endpoint.connect(factory)
        await client.login(username.encode("utf-8"),
                           password.encode("utf-8"))
        await client.select("INBOX")
        info = await client.fetchEnvelope(imap4.MessageSet(1))
        print("First message subject:", info[1]["ENVELOPE"][1])
    except:
        print("IMAP4 client interaction failed")
        print(failure.Failure().getTraceback())

task.react(lambda *a, **k: defer.ensureDeferred(main(*a, **k)), sys.argv[1:])
                  

具體可以用自己支持IMAP的郵箱做測試

SSH客戶端

Twisted 包含 一個SSH 客戶端 和 服務器, "conch" (比如: Twisted Shell).

import sys, os

from twisted.internet import protocol, defer, endpoints, task
from twisted.conch.endpoints import SSHCommandClientEndpoint


async def main(reactor, username="tacey", sshhost="192.168.1.123", portno="22"):
    envAgent = endpoints.UNIXClientEndpoint(reactor, os.environ["SSH_AUTH_SOCK"])
    endpoint = SSHCommandClientEndpoint.newConnection(
        reactor, "echo '你好,世界'", username, sshhost,
        int(portno), agentEndpoint=envAgent,
    )

    class ShowOutput(protocol.Protocol):
        received = b""

        def dataReceived(self, data):
            self.received += data

        def connectionLost(self, reason):
            finished.callback(self.received)

    finished = defer.Deferred()
    factory = protocol.Factory.forProtocol(ShowOutput)
    await endpoint.connect(factory)
    print("SSH 響應:", await finished)


task.react(lambda *a, **k: defer.ensureDeferred(main(*a, **k)), sys.argv[1:])

(可能需要安裝bcrypt——pip install bcrypt

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章