我认为
Twisted
更适合协议实现。无论如何,在Python中,函数和方法都是一流对象,这意味着您可以将它们存储在字典中。您还可以使用
functools.partial
将带有参数的函数绑定到字典键上。您可以使用它来实现转换。每个状态应该是一个包含字典的函数,其中键是可能的输入状态,值是输出状态。然后,您可以轻松地从一个状态跳到另一个状态。为了利用Tornado循环的下一个状态,而不是直接调用,应该使用
ioloop.IOLoop.instance().add_callback
注册回调。
接受语言a*b*c的自动机的示例实现:
import errno
import functools
import socket
from tornado import ioloop, iostream
class Communicator(object):
def connection_ready(self, sock, fd, events):
while True:
try:
connection, address = sock.accept()
except socket.error, e:
if e[0] not in (errno.EWOULDBLOCK, errno.EAGAIN):
raise
return
connection.setblocking(0)
self.stream = iostream.IOStream(connection)
self.stream.read_until(delimiter='\n', callback=self.initial_state)
def initial_state(self, msg):
msg = msg.rstrip()
print "entering initial state with message: %s" % msg
transitions = {
'a' : functools.partial(ioloop.IOLoop.instance().add_callback, self.state_a, msg),
'b' : functools.partial(ioloop.IOLoop.instance().add_callback, self.state_b, msg),
'c' : functools.partial(ioloop.IOLoop.instance().add_callback, self.final_state, msg)
}
try:
transitions[msg[0]]()
except:
self.stream.write("Aborted (wrong input)\n", self.stream.close)
def state_a(self, msg):
print "entering state a with message: %s" % msg
transitions = {
'a' : functools.partial(ioloop.IOLoop.instance().add_callback, self.stream.write, "got a\n", functools.partial(self.state_a, msg[1:])),
'b' : functools.partial(ioloop.IOLoop.instance().add_callback, self.state_b, msg),
'c' : functools.partial(ioloop.IOLoop.instance().add_callback, self.final_state, msg[1:])
}
try:
transitions[msg[0]]()
except:
self.stream.write("Aborted (wrong input)\n", self.stream.close)
def state_b(self, msg):
print "entering state b with message: %s" % msg
transitions = {
'a' : functools.partial(ioloop.IOLoop.instance().add_callback, self.state_a, msg),
'b' : functools.partial(ioloop.IOLoop.instance().add_callback, self.stream.write, "got b\n", functools.partial(self.state_a, msg[1:])),
'c' : functools.partial(ioloop.IOLoop.instance().add_callback, self.final_state, msg[1:])}
try:
transitions[msg[0]]()
except:
self.stream.write("Aborted (wrong input)\n" , self.stream.close)
def final_state(self, msg):
print "entering final state with message: %s" % msg
self.stream.write("Finished properly with message %s\n" % msg, self.stream.close)
if __name__ == '__main__':
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setblocking(0)
sock.bind(("", 8000))
sock.listen(5000)
communicator = Communicator()
io_loop = ioloop.IOLoop.instance()
callback = functools.partial(communicator.connection_ready, sock)
io_loop.add_handler(sock.fileno(), callback, io_loop.READ)
try:
io_loop.start()
except KeyboardInterrupt:
io_loop.stop()
print "exited cleanly"
使用Netcat进行会话:
$ nc localhost 8000
aaaaa
got a
got a
got a
got a
got a
Aborted (wrong input)
$ nc localhost 8000
abababab
got a
got b
got a
got b
got a
got b
got a
got b
Aborted (wrong input)
$ nc localhost 8000
aaabbbc
got a
got a
got a
got b
got b
got b
Finished properly with message
$ nc localhost 8000
abcabc
got a
got b
Finished properly with message abc