文档章节

基于Twisted的网络服务器编写

舒运
 舒运
发布于 2017/06/21 00:16
字数 2024
阅读 87
收藏 1
点赞 0
评论 0

开始

此文档解释了如何使用twisted来实现网络协议栈的解析和TCP服务的处理。(相同的代码可以在SSL和Unix socket servers中复用。)

protocol处理类一般从twisted.internet.protocol.Protocol中继承为子类,大多数的protocol handlers要么从这个类继承,或者从相应的子类中再继承。Protocol类的一个实例是每次连接后的实例化,根据实际情况,当连接结束之后被释放。这意味着这种持久性的配置并非永存于Protocol中。

这种永久性的配置其实保存于Factory类中,一般它从 twisted.internet.protocol.Factory 中继承。这个工厂类的buildProtocol()方法在每次连接到来时用于构建一个Protocol对象。

在通常情况下,对多端口或者网络地址上来提供相同的服务是非常有用的。这就是为何工厂Factory并不提供监听连接的原因,实际上它并不知道任何关于网络方面的事情。

Protocols

上面提到,它在大多数代码中存在的形式是伴随着一种附加类和函数。Twisted的protocol主要以异步的方式处理数据:当网络中的事件到达时,协议才响应事件。事件到达后,会调用协议中的方法。以下是个简单的例子:

from twisted.internet.protocol import Protocol  
class Echo(Protocol):  
    def dataReceived(self, data):  
        self.transport.write(data)  

这是一个非常简单的协议。它只是简单的回写所有接收到的数据,并不响应任何事件。以下是另外一个响应事件的协议:

from twisted.internet.protocol import Protocol  
class QOTD(Protocol):  
def connectionMade(self):  
        self.transport.write("An apple a day keeps the doctor away\r\n")   
        self.transport.loseConnection() 

 

这个协议有一个双引号来响应建立的初始连接,然后结束这个连接。connectionMade是一个事件,通常创建于对象的连接发生后,以及所有的初始greetings(如上QOTD协议,它主要基于RFC865).connectionLost事件是对已经处理的所有连接请求指定对象的销毁。以下是例子:

from twisted.internet.protocol import Protocol  
class Echo(Protocol):  
    def __init__(self, factory):  
        self.factory = factory  
    def connectionMade(self):  
        self.factory.numProtocols = self.factory.numProtocols+1   
        self.transport.write(  
            "Welcome! There are currently %d open connections.\n" %  
            (self.factory.numProtocols,))  
    def connectionLost(self, reason):  
        self.factory.numProtocols = self.factory.numProtocols-1  
    def dataReceived(self, data):  
        self.transport.write(data)  

这里的connectionMade和connectionLost事件相互合作在一个共享对象factory中存放一个活动的协议对象总数。当创建一个实例时Factory必须传递给Echo.__init__。Factory用于共享当前的一些状态,这些状态将超出任何给定连接的生命周期。在下一部分内容中你将看到为何把这个对象称为”factory”

loseConnection()和abortConnection()

上述的代码中,loseConnection()在写入传输通道后被调用。loseConnection()方法在所有的数据被Twisted写入操作系统后,它将会关闭连接。所以在这种情况下不用担心通道写入的的数据会被丢失,它是很安全的

如果”生产者”被用于这种通信传输上时,一旦“生产者”被注销,loseConnection()将仅仅关闭连接,传输的数据有可能未成功写入。

在多数情况下,等待所有的数据被成功写出并非我们所想象。由于网络的失效,bug或者其它连接的恶意攻击,即使loseConnection被调用,连接还建立的情况下,这时写入传输通道的数据有时可能依旧无法传递。在这种情况下,abortConnection可以被很好的使用。它不管当前未传输的缓存中是否有数据,或者在“生产者”依旧处于注册的状态下,它都将立刻关闭连接。注意:abortConnection仅仅在高于或等于Twisted11.1版本上才有效。

Using the Protocol

在这部分,你将学会怎样去运行一个使用你自己的协议的服务器。以前面讨论过QOTD服务器,下面将运行这个服务器:

from twisted.internet.protocol import Factory  
from twisted.internet.endpoints import TCP4ServerEndpoint  
from twisted.internet import reactor  
class QOTDFactory(Factory):  
    def buildProtocol(self, addr):  
        return QOTD()  
# 8007 is the port you want to run under. Choose something >1024  
endpoint = TCP4ServerEndpoint(reactor, 8007)  
endpoint.listen(QOTDFactory())  
reactor.run()  

在这个例子中,它创建了一个协议工厂QOTDFactory,它的主要任务是创建一个QOTD协议的实例,所以通过buildProtocol()方法来返回一个QOTD类的实例。然后,开始监听TCP端口,所以让TCP4ServerEndpoint来识别要绑定的端口地址,最后给它的listen方法传递一个协议工厂对象即可。

由于这是个简短的代码,不需要其它任何东西来启动Twisted reactor. Endpoint.listen告诉reactor通过使用一个特殊的协议(由协议工厂实例化的)来处理连接到endpoint的地址的所有连接请求,但是reactor在它要做事之前必须先run一下,所以reactor.run()用于启动reactor然后一直等待你所期望的到达此端口的任何连接请求。

通过Control-C或者调用reactor.stop()来停止reactor.

 

Helper Protocols

许多协议创建于类似的抽象的底层协议。最流行的互联网协议是基于行的。“行”经常用CR-LF来终止。然而,更多的其它协议是混合的,他们有基于行的部分和原始数据部分。这样的例子包括Http/1.1和Freenet协议。

在大多数情况下,会有LineReceiver协议,这个协议将区分两个不同的事件处理: lineReceived和rawDataReceived.缺省情况下每行数据到达行,lineReceived会被调用。然而,如果setRawMode被调用后,协议将采用rawDataReceived方法来接收数据,除非再调用setLineMode来切换到缺省情况。它也提供sendLine方法,它在传传的数据后面会自动的增加”\r\n”

以下是个使用行接收的例子:

from twisted.protocols.basic import LineReceiver  
class Answer(LineReceiver):  
    answers = {'How are you?': 'Fine', None : "I don't know what you mean"}  
    def lineReceived(self, line):  
        if self.answers.has_key(line):  
            self.sendLine(self.answers[line])  
        else:  
            self.sendLine(self.answers[None])  

注意:在这种情况下就不要再增加\r\n了。

Factories

简单协议创建

对于一个工厂来说,它的主要工作是实例化某个指定协议类的实化。有一个更简单的方法来实现一个工厂。缺省的实现是通过buildProtocol方法调用工厂的protocol属性来创建一个协议实例。这种方式可以让每种协议进行各种的访问,做各种修改,来完成这种配置。以下是代码:

from twisted.internet.protocol import Factory, Protocol  
from twisted.internet.endpoints import TCP4ServerEndpoint  
from twisted.internet import reactor  
class QOTD(Protocol):  
    def connectionMade(self):  
        # self.factory was set by the factory's default buildProtocol:  
        self.transport.write(self.factory.quote + '\r\n')  
        self.transport.loseConnection()  
class QOTDFactory(Factory):  
    # This will be used by the default buildProtocol to create new protocols:  
    protocol = QOTD  
    def __init__(self, quote=None):  
        self.quote = quote or 'An apple a day keeps the doctor away'  
endpoint = TCP4ServerEndpoint(reactor, 8007)  
endpoint.listen(QOTDFactory("configurable quote"))  
reactor.run()  

工厂的启动与关闭

工厂具有两种方式来执行相关应用的创建与销毁。以下是例子:

from twisted.internet.protocol import Factory  
from twisted.protocols.basic import LineReceiver  
class LoggingProtocol(LineReceiver):  
    def lineReceived(self, line):  
        self.factory.fp.write(line+'\n')  
class LogfileFactory(Factory):  
    protocol = LoggingProtocol  
    def __init__(self, fileName):  
        self.file = fileName  
    def startFactory(self):  
        self.fp = open(self.file, 'a')  
    def stopFactory(self):  
        self.fp.close()  

综合

以下是最后一个例子,有一个最简单的聊天服务器允许多用户选择用户名然后与其它用户进行通信。它演示了在工厂中如何使用共享的状态,共享每个独立协议的状态机,以及在不同协议之间的通信情况。

from twisted.internet.protocol import Factory  
from twisted.protocols.basic import LineReceiver  
from twisted.internet import reactor  
  
class Chat(LineReceiver):  
    def __init__(self, users):  
        self.users = users  
        self.name = None  
        self.state = "GETNAME"  
  
    def connectionMade(self):  
        self.sendLine("What's your name?")  
  
    def connectionLost(self, reason):  
        if self.users.has_key(self.name):  
            del self.users[self.name]  
  
    def lineReceived(self, line):  
        if self.state == "GETNAME":  
            self.handle_GETNAME(line)  
        else:  
            self.handle_CHAT(line)  
  
    def handle_GETNAME(self, name):  
        if self.users.has_key(name):  
            self.sendLine("Name taken, please choose another.")  
            return  
        self.sendLine("Welcome, %s!" % (name,))  
        self.name = name  
        self.users[name] = self  
        self.state = "CHAT"  
  
    def handle_CHAT(self, message):  
        message = "<%s> %s" % (self.name, message)  
        for name, protocol in self.users.iteritems():  
            if protocol != self:  
                protocol.sendLine(message)  
  
class ChatFactory(Factory):  
  
    def __init__(self):  
        self.users = {} # maps user names to Chat instances  
  
    def buildProtocol(self, addr):  
        return Chat(self.users)  
  
reactor.listenTCP(8123, ChatFactory())  
reactor.run()  

唯一不熟的API有可能就是listenTCP,这是一个将工厂连接到网络的方法。

以下是简单的聊天会话记录:

© 著作权归作者所有

共有 人打赏支持
舒运
粉丝 7
博文 213
码字总数 510016
作品 0
深圳
【转】Python Twisted介绍

Python Twisted介绍 作者:Jessica McKellar 原文链接   Twisted是用Python实现的基于事件驱动的网络引擎框架。Twisted诞生于2000年初,在当时的网络游戏开发者看来,无论他们使用哪种语言...

罗兵 ⋅ 2016/06/27 ⋅ 0

zg手册 之 twisted 开发(1)-- twisted 框架介绍

异步非阻塞框架 twisted 是一个事件驱动的网络开发框架,使用 python 开发。 twisted 框架编写的服务器有几个基本的元素: 应用程序对象(application):管理应用程序资源的对象,一个应用程序...

东昕 ⋅ 2014/06/21 ⋅ 0

Python网络编程笔记

一、说明 使用套接字进行网络编程,需要先了解一些有关网络编程的背景信息。 1、客户端/服务器架构: 服务器为一个或多个客户端提供所需的服务,存在的目的就是等待客户端的请求,并响应它们,...

PeanutLike ⋅ 2016/12/01 ⋅ 0

Firefly —— 国产的 Python 游戏服务器框架

Firefly是免费、开源、稳定、快速扩展、能 “热更新”的分布式游戏服务器端框架,采用Python编写,基于Twisted框架开发。它包括了开发框架和数据库缓存服务等各种游戏服务器基础服务,节省大...

oschina ⋅ 2013/08/19 ⋅ 0

jamiesun/PandaRSS

#PandaRSS PandaRSS 是一个基于 ToughRADIUS V2版本 API 的自助服务系统。 快速指南 运行环境 Linux Python 2.7 pip Twisted>=15.0.0 可选 bottle>=0.12.7 安装 pip install -U https://git......

jamiesun ⋅ 2016/04/29 ⋅ 0

【重要】基于Gevent的firefly重要迭代版本推出

目前使用者最多的开源游戏服务器端框架Firefly推出了基于Gevent的重要迭代版本,不过目前还处在alpha阶段。Firefly团队使用Gevent完整实现了之前Firefly所依赖twisted内的部分,并还原了api...

大鸡蛋 ⋅ 2014/03/20 ⋅ 6

(转)Twisted :第一部分:初步认识Twisted

前言: 最近有人在Twisted邮件列表中提出诸如”为任务紧急的人提供一份Twisted介绍”的的需求。值得提前透露的是,这个序列并不会如他们所愿.尤其是介绍Twisted框架和基于Python 的异步编程而...

水果糖 ⋅ 2016/01/27 ⋅ 0

[Python] Twiested - 基于事件驱动的网络编程

介绍 twisted 是python下一个事件驱动的网络引擎库, 支持很多种的协议. 它包含了一个web服务, 多种IM客户端,服务端, 邮件服务协议. 由于规模庞大, twisted分成了几个sub-project. 一起或者分...

长平狐 ⋅ 2013/06/03 ⋅ 0

Python 爬虫工具列表

本文转载自伯乐在线:http://python.jobbole.com/82633/ 这个列表包含与网页抓取和数据处理的Python库 网络 通用 urllib -网络库(stdlib)。 requests -网络库。 grab - 网络库(基于pycurl)...

好铁 ⋅ 2016/03/16 ⋅ 1

(转) Twisted : 第十二部分 改进诗歌下载服务器

新的服务器实现 这里我们要新写一个Twisted版的服务器。然后,再来讨论一些Deferred的新功能。 在第九、十部分,我们提出了诗歌转换引擎这个概念。由于其实现太过简单,因此我们用随机选择来...

水果糖 ⋅ 2016/01/27 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

个人博客的运营模式能否学习TMALL天猫质量为上?

心情随笔|个人博客的运营模式能否学习TMALL天猫质量为上? 中国的互联网已经发展了很多年了,记得在十年前,个人博客十分流行,大量的人都在写博客,而且质量还不错,很多高质量的文章都是在...

原创小博客 ⋅ 今天 ⋅ 0

JavaScript零基础入门——(十一)JavaScript的DOM操作

JavaScript零基础入门——(十一)JavaScript的DOM操作 大家好,欢迎回到我们的JavaScript零基础入门。最近有些同学问我说,我讲的的比书上的精简不少。其实呢,我主要讲的是我在开发中经常会...

JandenMa ⋅ 今天 ⋅ 0

volatile和synchronized的区别

volatile和synchronized的区别 在讲这个之前需要先了解下JMM(Java memory Model :java内存模型):并发过程中如何处理可见性、原子性、有序性的问题--建立JMM模型 详情请看:https://baike.b...

MarinJ_Shao ⋅ 今天 ⋅ 0

深入分析Kubernetes Critical Pod(一)

Author: xidianwangtao@gmail.com 摘要:大家在部署Kubernetes集群AddOn组件的时候,经常会看到Annotation scheduler.alpha.kubernetes.io/critical-pod"="",以表示这是一个关键服务,那你知...

WaltonWang ⋅ 今天 ⋅ 0

原子性 - synchronized关键词

原子性概念 原子性提供了程序的互斥操作,同一时刻只能有一个线程能对某块代码进行操作。 原子性的实现方式 在jdk中,原子性的实现方式主要分为: synchronized:关键词,它依赖于JVM,保证了同...

dotleo ⋅ 今天 ⋅ 0

【2018.06.22学习笔记】【linux高级知识 14.4-15.3】

14.4 exportfs命令 14.5 NFS客户端问题 15.1 FTP介绍 15.2/15.3 使用vsftpd搭建ftp

lgsxp ⋅ 今天 ⋅ 0

JeeSite 4.0 功能权限管理基础(Shiro)

Shiro是Apache的一个开源框架,是一个权限管理的框架,实现用户认证、用户授权等。 只要有用户参与一般都要有权限管理,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户...

ThinkGem ⋅ 昨天 ⋅ 0

python f-string 字符串格式化

主要内容 从Python 3.6开始,f-string是格式化字符串的一种很好的新方法。与其他格式化方式相比,它们不仅更易读,更简洁,不易出错,而且速度更快! 在本文的最后,您将了解如何以及为什么今...

阿豪boy ⋅ 昨天 ⋅ 0

Python实现自动登录站点

如果我们想要实现自动登录,那么我们就需要能够驱动浏览器(比如谷歌浏览器)来实现操作,ChromeDriver 刚好能够帮助我们这一点(非谷歌浏览器的驱动有所不同)。 一、确认软件版本 首先我们...

blackfoxya ⋅ 昨天 ⋅ 0

线性回归原理和实现基本认识

一:介绍 定义:线性回归在假设特证满足线性关系,根据给定的训练数据训练一个模型,并用此模型进行预测。为了了解这个定义,我们先举个简单的例子;我们假设一个线性方程 Y=2x+1, x变量为商...

wangxuwei ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部