- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Python下的twisted框架入门指引由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
什么是twisted?
twisted是一个用python语言写的事件驱动的网络框架,他支持很多种协议,包括UDP,TCP,TLS和其他应用层协议,比如HTTP,SMTP,NNTM,IRC,XMPP/Jabber。 非常好的一点是twisted实现和很多应用层的协议,开发人员可以直接只用这些协议的实现。其实要修改Twisted的SSH服务器端实现非常简单。很多时候,开发人员需要实现protocol类.
一个Twisted程序由reactor发起的主循环和一些回调函数组成。当事件发生了,比如一个client连接到了server,这时候服务器端的事件会被触发执行。 用Twisted写一个简单的TCP服务器 。
下面的代码是一个TCPServer,这个server记录客户端发来的数据信息.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
=
=
=
=
code1.py
=
=
=
=
import
sys
from
twisted.internet.protocol
import
ServerFactory
from
twisted.protocols.basic
import
LineReceiver
from
twisted.python
import
log
from
twisted.internet
import
reactor
class
CmdProtocol(LineReceiver):
delimiter
=
'\n'
def
connectionMade(
self
):
self
.client_ip
=
self
.transport.getPeer()[
1
]
log.msg(
"Client connection from %s"
%
self
.client_ip)
if
len
(
self
.factory.clients) >
=
self
.factory.clients_max:
log.msg(
"Too many connections. bye !"
)
self
.client_ip
=
None
self
.transport.loseConnection()
else
:
self
.factory.clients.append(
self
.client_ip)
def
connectionLost(
self
, reason):
log.msg(
'Lost client connection. Reason: %s'
%
reason)
if
self
.client_ip:
self
.factory.clients.remove(
self
.client_ip)
def
lineReceived(
self
, line):
log.msg(
'Cmd received from %s : %s'
%
(
self
.client_ip, line))
class
MyFactory(ServerFactory):
protocol
=
CmdProtocol
def
__init__(
self
, clients_max
=
10
):
self
.clients_max
=
clients_max
self
.clients
=
[]
log.startLogging(sys.stdout)
reactor.listenTCP(
9999
, MyFactory(
2
))
reactor.run()
|
下面的代码至关重要:
1
2
|
from
twisted.internet
import
reactor
reactor.run()
|
这两行代码会启动reator的主循环.
在上面的代码中我们创建了"ServerFactory"类,这个工厂类负责返回“CmdProtocol”的实例。 每一个连接都由实例化的“CmdProtocol”实例来做处理。 Twisted的reactor会在TCP连接上后自动创建CmdProtocol的实例。如你所见,protocol类的方法都对应着一种事件处理.
当client连上server之后会触发“connectionMade"方法,在这个方法中你可以做一些鉴权之类的操作,也可以限制客户端的连接总数。每一个protocol的实例都有一个工厂的引用,使用self.factory可以访问所在的工厂实例.
上面实现的”CmdProtocol“是twisted.protocols.basic.LineReceiver的子类,LineReceiver类会将客户端发送的数据按照换行符分隔,每到一个换行符都会触发lineReceived方法。稍后我们可以增强LineReceived来解析命令.
Twisted实现了自己的日志系统,这里我们配置将日志输出到stdout 。
当执行reactor.listenTCP时我们将工厂绑定到了9999端口开始监听.
1
2
3
4
5
6
|
user@lab:~
/
TMP$ python code1.py
2011
-
08
-
29
13
:
32
:
32
+
0200
[
-
] Log opened.
2011
-
08
-
29
13
:
32
:
32
+
0200
[
-
] __main__.MyFactory starting on
9999
2011
-
08
-
29
13
:
32
:
32
+
0200
[
-
] Starting factory <__main__.MyFactory instance at
0x227e320
2011
-
08
-
29
13
:
32
:
35
+
0200
[__main__.MyFactory] Client connection
from
127.0
.
0.1
2011
-
08
-
29
13
:
32
:
38
+
0200
[CmdProtocol,
0
,
127.0
.
0.1
] Cmd received
from
127.0
.
0.1
: hello server
|
使用Twisted来调用外部进程 。
下面我们给前面的server添加一个命令,通过这个命令可以读取/var/log/syslog的内容 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
import
sys
import
os
from
twisted.internet.protocol
import
ServerFactory, ProcessProtocol
from
twisted.protocols.basic
import
LineReceiver
from
twisted.python
import
log
from
twisted.internet
import
reactor
class
TailProtocol(ProcessProtocol):
def
__init__(
self
, write_callback):
self
.write
=
write_callback
def
outReceived(
self
, data):
self
.write(
"Begin lastlog\n"
)
data
=
[line
for
line
in
data.split(
'\n'
)
if
not
line.startswith(
'=='
)]
for
d
in
data:
self
.write(d
+
'\n'
)
self
.write(
"End lastlog\n"
)
def
processEnded(
self
, reason):
if
reason.value.exitCode !
=
0
:
log.msg(reason)
class
CmdProtocol(LineReceiver):
delimiter
=
'\n'
def
processCmd(
self
, line):
if
line.startswith(
'lastlog'
):
tailProtocol
=
TailProtocol(
self
.transport.write)
reactor.spawnProcess(tailProtocol,
'/usr/bin/tail'
, args
=
[
'/usr/bin/tail'
,
'-10'
,
'/var/log/syslog'
])
elif
line.startswith(
'exit'
):
self
.transport.loseConnection()
else
:
self
.transport.write(
'Command not found.\n'
)
def
connectionMade(
self
):
self
.client_ip
=
self
.transport.getPeer()[
1
]
log.msg(
"Client connection from %s"
%
self
.client_ip)
if
len
(
self
.factory.clients) >
=
self
.factory.clients_max:
log.msg(
"Too many connections. bye !"
)
self
.client_ip
=
None
self
.transport.loseConnection()
else
:
self
.factory.clients.append(
self
.client_ip)
def
connectionLost(
self
, reason):
log.msg(
'Lost client connection. Reason: %s'
%
reason)
if
self
.client_ip:
self
.factory.clients.remove(
self
.client_ip)
def
lineReceived(
self
, line):
log.msg(
'Cmd received from %s : %s'
%
(
self
.client_ip, line))
self
.processCmd(line)
class
MyFactory(ServerFactory):
protocol
=
CmdProtocol
def
__init__(
self
, clients_max
=
10
):
self
.clients_max
=
clients_max
self
.clients
=
[]
log.startLogging(sys.stdout)
reactor.listenTCP(
9999
, MyFactory(
2
))
reactor.run()
|
在上面的代码中,没从客户端接收到一行内容后会执行processCmd方法,如果收到的一行内容是exit命令,那么服务器端会断开连接,如果收到的是lastlog,我们要吐出一个子进程来执行tail命令,并将tail命令的输出重定向到客户端。这里我们需要实现ProcessProtocol类,需要重写该类的processEnded方法和outReceived方法。在tail命令有输出时会执行outReceived方法,当进程退出时会执行processEnded方法.
如下是执行结果样例:
1
2
3
4
5
6
7
8
9
|
user@lab:~
/
TMP$ python code2.py
2011
-
08
-
29
15
:
13
:
38
+
0200
[
-
] Log opened.
2011
-
08
-
29
15
:
13
:
38
+
0200
[
-
] __main__.MyFactory starting on
9999
2011
-
08
-
29
15
:
13
:
38
+
0200
[
-
] Starting factory <__main__.MyFactory instance at
0x1a5a3f8
>
2011
-
08
-
29
15
:
13
:
47
+
0200
[__main__.MyFactory] Client connection
from
127.0
.
0.1
2011
-
08
-
29
15
:
13
:
58
+
0200
[CmdProtocol,
0
,
127.0
.
0.1
] Cmd received
from
127.0
.
0.1
: test
2011
-
08
-
29
15
:
14
:
02
+
0200
[CmdProtocol,
0
,
127.0
.
0.1
] Cmd received
from
127.0
.
0.1
: lastlog
2011
-
08
-
29
15
:
14
:
05
+
0200
[CmdProtocol,
0
,
127.0
.
0.1
] Cmd received
from
127.0
.
0.1
: exit
2011
-
08
-
29
15
:
14
:
05
+
0200
[CmdProtocol,
0
,
127.0
.
0.1
] Lost client connection. Reason: [Failure instance: Traceback (failure with no frames): <
class
'twisted.internet.error.ConnectionDone'
>: Connection was closed cleanly.
|
可以使用下面的命令作为客户端发起命令:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
user@lab:~$ netcat
127.0
.
0.1
9999
test
Command
not
found.
lastlog
Begin lastlog
Aug
29
15
:
02
:
03
lab sSMTP[
5919
]: Unable to locate mail
Aug
29
15
:
02
:
03
lab sSMTP[
5919
]: Cannot
open
mail:
25
Aug
29
15
:
02
:
03
lab CRON[
4945
]: (CRON) error (grandchild
#4947 failed with exit status 1)
Aug
29
15
:
02
:
03
lab sSMTP[
5922
]: Unable to locate mail
Aug
29
15
:
02
:
03
lab sSMTP[
5922
]: Cannot
open
mail:
25
Aug
29
15
:
02
:
03
lab CRON[
4945
]: (logcheck) MAIL (mailed
1
byte of output; but got status
0x0001
,
#012)
Aug
29
15
:
05
:
01
lab CRON[
5925
]: (root) CMD (command
-
v debian
-
sa1 >
/
dev
/
null && debian
-
sa1
1
1
)
Aug
29
15
:
10
:
01
lab CRON[
5930
]: (root) CMD (test
-
x
/
usr
/
lib
/
atsar
/
atsa1 &&
/
usr
/
lib
/
atsar
/
atsa1)
Aug
29
15
:
10
:
01
lab CRON[
5928
]: (CRON) error (grandchild
#5930 failed with exit status 1)
Aug
29
15
:
13
:
21
lab pulseaudio[
3361
]: ratelimit.c:
387
events suppressed
End lastlog
exit
|
使用Deferred对象 。
reactor是一个循环,这个循环在等待事件的发生。 这里的事件可以是数据库操作,也可以是长时间的计算操作。 只要这些操作可以返回一个Deferred对象。Deferred对象可以自动得在事件发生时触发回调函数。reactor会block当前代码的执行.
现在我们要使用Defferred对象来计算SHA1哈希.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
import
sys
import
os
import
hashlib
from
twisted.internet.protocol
import
ServerFactory, ProcessProtocol
from
twisted.protocols.basic
import
LineReceiver
from
twisted.python
import
log
from
twisted.internet
import
reactor, threads
class
TailProtocol(ProcessProtocol):
def
__init__(
self
, write_callback):
self
.write
=
write_callback
def
outReceived(
self
, data):
self
.write(
"Begin lastlog\n"
)
data
=
[line
for
line
in
data.split(
'\n'
)
if
not
line.startswith(
'=='
)]
for
d
in
data:
self
.write(d
+
'\n'
)
self
.write(
"End lastlog\n"
)
def
processEnded(
self
, reason):
if
reason.value.exitCode !
=
0
:
log.msg(reason)
class
HashCompute(
object
):
def
__init__(
self
, path, write_callback):
self
.path
=
path
self
.write
=
write_callback
def
blockingMethod(
self
):
os.path.isfile(
self
.path)
data
=
file
(
self
.path).read()
# uncomment to add more delay
# import time
# time.sleep(10)
return
hashlib.sha1(data).hexdigest()
def
compute(
self
):
d
=
threads.deferToThread(
self
.blockingMethod)
d.addCallback(
self
.ret)
d.addErrback(
self
.err)
def
ret(
self
, hdata):
self
.write(
"File hash is : %s\n"
%
hdata)
def
err(
self
, failure):
self
.write(
"An error occured : %s\n"
%
failure.getErrorMessage())
class
CmdProtocol(LineReceiver):
delimiter
=
'\n'
def
processCmd(
self
, line):
if
line.startswith(
'lastlog'
):
tailProtocol
=
TailProtocol(
self
.transport.write)
reactor.spawnProcess(tailProtocol,
'/usr/bin/tail'
, args
=
[
'/usr/bin/tail'
,
'-10'
,
'/var/log/syslog'
])
elif
line.startswith(
'comphash'
):
try
:
useless, path
=
line.split(
' '
)
except
:
self
.transport.write(
'Please provide a path.\n'
)
return
hc
=
HashCompute(path,
self
.transport.write)
hc.compute()
elif
line.startswith(
'exit'
):
self
.transport.loseConnection()
else
:
self
.transport.write(
'Command not found.\n'
)
def
connectionMade(
self
):
self
.client_ip
=
self
.transport.getPeer()[
1
]
log.msg(
"Client connection from %s"
%
self
.client_ip)
if
len
(
self
.factory.clients) >
=
self
.factory.clients_max:
log.msg(
"Too many connections. bye !"
)
self
.client_ip
=
None
self
.transport.loseConnection()
else
:
self
.factory.clients.append(
self
.client_ip)
def
connectionLost(
self
, reason):
log.msg(
'Lost client connection. Reason: %s'
%
reason)
if
self
.client_ip:
self
.factory.clients.remove(
self
.client_ip)
def
lineReceived(
self
, line):
log.msg(
'Cmd received from %s : %s'
%
(
self
.client_ip, line))
self
.processCmd(line)
class
MyFactory(ServerFactory):
protocol
=
CmdProtocol
def
__init__(
self
, clients_max
=
10
):
self
.clients_max
=
clients_max
self
.clients
=
[]
log.startLogging(sys.stdout)
reactor.listenTCP(
9999
, MyFactory(
2
))
reactor.run()
|
blockingMethod从文件系统读取一个文件计算SHA1,这里我们使用twisted的deferToThread方法,这个方法返回一个Deferred对象。这里的Deferred对象是调用后马上就返回了,这样主进程就可以继续执行处理其他的事件。当传给deferToThread的方法执行完毕后会马上触发其回调函数。如果执行中出错,blockingMethod方法会抛出异常。如果成功执行会通过hdata的ret返回计算的结果。 推荐的twisted阅读资料 。
http://twistedmatrix.com/documents/current/core/howto/defer.html http://twistedmatrix.com/documents/current/core/howto/process.html http://twistedmatrix.com/documents/current/core/howto/servers.html 。
API文档:
http://twistedmatrix.com/documents/current/api/twisted.html 。
最后此篇关于Python下的twisted框架入门指引的文章就讲到这里了,如果你想了解更多关于Python下的twisted框架入门指引的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
Hive —— 入门 Hive介绍 Apache Hive是一款建立在Hadoop之上的开源数据仓库系统,可以将存储在Hadoop文件中的结构化、半结构化数据文件映射为一张数据库表,基于表提供了一
HBase —— 入门 HBase介绍 HBase是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”
零:前端目前形势 前端的发展史 HTML(5)、CSS(3)、JavaScript(ES5、ES6):编写一个个的页面 -> 给后端(PHP、Python、Go、Java) ->
在本教程中,您将了解在计算机上运行 JavaScript 的不同方法。 JavaScript 是一种流行的编程语言,具有广泛的应用程序。 JavaScript 以前主要用于使网页具有交
我曾经是一个对编程一窍不通的小白,但因为对互联网世界的好奇心和求知欲的驱使,我踏入了编程的殿堂。在学习的过程中,我发现了一门神奇的编程语言——Python。Python有着简洁、易读的语法,让初学者能
嗨,亲爱的读者们! 今天我要给大家分享一些关于Python爬虫的小案例。你是否曾为了获取特定网页上的数据而烦恼过?或者是否好奇如何从网页中提取信息以供自己使用?那么,这篇文章将会给你一些启示和灵感。
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 8 年前。 Improv
我想创建一个像https://apprtc.appspot.com/?r=04188292这样的应用程序。我对 webrtc 了解一点,但无法掌握 google app-engine。如何为 java
我刚刚开始使用 Python 并编写了一个简单的周边程序。但是,每当我在终端中键入 python perimeter.py 时,都会收到以下错误,我不知道如何解决。 >>> python perime
Redis有5个基本数据结构,string、list、hash、set和zset。它们是日常开发中使用频率非常高应用最为广泛的数据结构,把这5个数据结构都吃透了,你就掌握了Redis应用知识的一半了
创建发布web项目 具体步骤: 1.在开发工具中创建一个dynamic web project helloword 2.在webContent中创建index.html文件 3.发布web应用到
如果你在 Ubuntu 上使用终端的时间很长,你可能会希望调整终端的字体和大小以获取一种良好的体验。 更改字体是一种最简单但最直观的 Linux 的终端自定义 的方法。让我
1. 前言 ADODB 是 Active Data Objects Data Base 的简称,它是一种 PHP 存取数据库的函式组件。现在 SFS3 系统 (校园自由软件交流网学务系统) 计划的
我对 neo4j 完全陌生,我很抱歉提出这样一个基本问题。我已经安装了neo4j,我正在使用shell“localhost:7474/webadmin/#/console/” 我正在寻找一个很好的例子
我正在阅读 ios 4 的核心音频,目的是构建一个小测试应用程序。 在这一点上,我对所有 api 的研究感到非常困惑。理想情况下,我想知道如何从两个 mp3 中提取一些样本到数组中。 然后在回调循环中
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是无关紧要的,因
我下载了 GNUStep并安装了它,但是我不确定在哪里可以找到 IDE。有谁知道什么程序可以用作 GNUStep IDE/从哪里获取它们?否则,有没有人知道有关如何创建和编译基本 GNUStep 程序
我正在尝试开始使用 Apache Solr,但有些事情我不清楚。通读tutorial ,我已经设置了一个正在运行的 Solr 实例。我感到困惑的是 Solr 的所有配置(架构等)都是 XML 格式的。
请问有没有关于如何开始使用 BruTile 的文档? 我目前正在使用 SharpMap,我需要预缓存切片以加快进程 最佳答案 我今天正在研究这个:)Mapsui项目site严重依赖 SharpMap
尽我所能,我无法让 CEDET 做任何事情。 Emacs 24.3。我下载了最新的 CEDET 快照。我从他的底部(不是这样)Gentle Introduction 中获取了 Alex Ott 的设置
我是一名优秀的程序员,十分优秀!