Penso che Twisted
sia più adatto per implementazioni di protocollo. Ad ogni modo, in Python le funzioni e i metodi sono oggetti di prima classe, il che significa che è possibile memorizzarli all'interno di dizionari. È inoltre possibile utilizzare functools.partial
per associare una funzione con argomenti a un tasto di dizionario. Puoi usarlo per implementare le transizioni. Ogni stato dovrebbe essere una funzione contenente un dizionario in cui le chiavi sono possibili stati di input e i valori sono stati di output. Quindi puoi facilmente passare da uno stato all'altro. Per utilizzare il ciclo Tornado, gli stati successivi, invece di essere chiamati direttamente, devono essere registrati come callback utilizzando ioloop.IOLoop.instance().add_callback
.
un esempio di implementazione automi accettare la lingua 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"
sessione utilizzando 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
C'è una domanda? – Veedrac
@Veedrac È meglio ora? –