+ All Categories
Home > Documents > Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic...

Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic...

Date post: 08-Jul-2020
Category:
Upload: others
View: 0 times
Download: 0 times
Share this document with a friend
21
LECTURE 16 Twisted
Transcript
Page 1: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

LECTURE 16 Twisted

Page 2: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

A SIMPLE TCP SERVER

To begin our introduction to Twisted, we’ll build a simple TCP server.

Page 3: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

REACTOR BASICS

At the core of any Twisted application is the reactor loop. The reactor loop works by waiting for events to occur and then calls the relevant event handler (“dispatches the event”). The simplest Twisted program is the following, which accesses the reactor object and starts it.

from twisted.internet import reactorreactor.run()

Page 4: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

REACTOR BASICS

At the core of any Twisted application is the reactor loop. The reactor loop works by waiting events to occur and then calls the relevant event handler (“dispatches the event”). The simplest Twisted program is the following, which accesses the reactor object and starts it.

The reactor loop runs in the main and only thread. Once we run the reactor, it assumes control of the program. If there is nothing to do (as is the case here), the reactor loop just sits idle, not consuming CPU resources.

from twisted.internet import reactor # Not created explicitly! Just import it. reactor.run()

Page 5: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

REACTOR BASICS

The reactor provides basic interfaces to a number of services, including network communications, threading, and event dispatching. There are several reactor options, each specialized for a particular application. The default reactor on most systems is a Select-based reactor.

To use a different reactor, you must “install” it.

from twisted.internet import pollreactorpollreactor.install() # When reactor is imported, it will be a pollreactor

from twisted.internet import reactor # Always import reactor right before you run itreactor.run()

Page 6: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

REACTOR BASICS

The core required functionality of a reactor is defined in twisted.internet.interfaces.IReactorCore. These include:

• run() – move the reactor to a “running” state. Starts the main loop.

• stop() – shutdown the reactor.

• callWhenRunning() – call a function when the reactor is running.

• addSystemEventTrigger() -- add a function to be called when a system event occurs.

• fireSystemEvent() -- fire a system-wide event.

There are additional methods defined in IReactorProcess, IReactorTCP, IReactorSocket, IReactorThreads, IReactorSSL, etc…The choice of reactor determine which/how these methods are implemented.

Page 7: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

REACTOR BASICS

Here’s an example Twisted program which registers a function call to be made when the reactor starts running.

Twisted has a basic logging mechanism defined in twisted.python.log.

import sysfrom twisted.python import loglog.startLogging(sys.stdout)

def func(x):log.msg("In func as event handler")log.msg(str(x))log.msg(“Shutting down now!")reactor.stop()

from twisted.internet import reactorreactor.callWhenRunning(func, “Hello!")reactor.run()

Page 8: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

REACTOR BASICS

$ python twist.py 2015-02-17 11:46:16-0500 [-] Log opened.2015-02-17 11:46:16-0500 [-] In func as event handler2015-02-17 11:46:16-0500 [-] Hello!2015-02-17 11:46:16-0500 [-] Shutting down now!2015-02-17 11:46:16-0500 [-] Main loop terminated

import sysfrom twisted.python import loglog.startLogging(sys.stdout)

def func(x):log.msg("In func as event handler")log.msg(str(x))log.msg(“Shutting down now!")reactor.stop()

from twisted.internet import reactorreactor.callWhenRunning(func, “Hello!")reactor.run()

Page 9: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

REACTOR BASICS

import sys, timefrom twisted.python import loglog.startLogging(sys.stdout)

def func(x):log.msg(str(x))now = time.localtime(time.time())log.msg(str(time.strftime("%y/%m/%d %H:%M:%S", now)))log.msg(“Shutting down now!")reactor.stop()

now = time.localtime(time.time())log.msg(str(time.strftime("%y/%m/%d %H:%M:%S", now)))from twisted.internet import reactorreactor.callLater(5, func, “Hello after 5 seconds!”)reactor.run()

Another example using the callLater scheduling method defined in IReactorTime.

Page 10: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

REACTOR BASICS

import sys, timefrom twisted.python import loglog.startLogging(sys.stdout)

def func(x):log.msg(str(x))now = time.localtime(time.time())log.msg(str(time.strftime("%y/%m/%d %H:%M:%S", now)))log.msg(“Shutting down now!")reactor.stop()

now = time.localtime(time.time())log.msg(str(time.strftime("%y/%m/%d %H:%M:%S", now)))from twisted.internet import reactorreactor.callLater(5, func, “Hello after 5 seconds!”)reactor.run()

$ python twist.py

2015-02-17 11:49:10-0500 [-] Log opened.

2015-02-17 11:49:10-0500 [-] 15/02/17 11:49:10

2015-02-17 11:49:15-0500 [-] Hello after 5 seconds!

2015-02-17 11:49:15-0500 [-] 15/02/17 11:49:15

2015-02-17 11:49:15-0500 [-] Shutting down now!

2015-02-17 11:49:15-0500 [-] Main loop terminated.

Page 11: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

REACTOR BASICS

import sys, timefrom twisted.python import loglog.startLogging(sys.stdout)

def func(x):log.msg(str(x))now = time.localtime(time.time())log.msg(str(time.strftime("%y/%m/%d %H:%M:%S",now)))log.msg("Fire FireworkEvent after 3 seconds…")reactor.callLater(3, reactor.fireSystemEvent, ‘FireworkEvent')

def Firework_CustomEventHandler():now = time.localtime(time.time())log.msg(str(time.strftime("%y/%m/%d %H:%M:%S",now)))log.msg(“BABY YOU’RE A FIIIIIIIIREWOOOOOORK")reactor.stop()

now = time.localtime(time.time())log.msg(str(time.strftime("%y/%m/%d %H:%M:%S",now)))from twisted.internet import reactorreactor.callLater(5, func, "func called after 5 sec")reactor.addSystemEventTrigger('during', ‘FireworkEvent', Firework_CustomEventHandler)reactor.run()

Let’s create a custom self-esteem boosting event.

Page 12: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

REACTOR BASICS

import sys, timefrom twisted.python import loglog.startLogging(sys.stdout)

def func(x):log.msg(str(x))now = time.localtime(time.time())log.msg(str(time.strftime("%y/%m/%d %H:%M:%S",now)))log.msg("Fire FireworkEvent after 3 seconds…")reactor.callLater(3, reactor.fireSystemEvent, ‘FireworkEvent')

def Firework_CustomEventHandler():now = time.localtime(time.time())log.msg(str(time.strftime("%y/%m/%d %H:%M:%S",now)))log.msg(“BABY YOU’RE A FIIIIIIIIREWOOOOOORK")reactor.stop()

now = time.localtime(time.time())log.msg(str(time.strftime("%y/%m/%d %H:%M:%S",now)))from twisted.internet import reactorreactor.callLater(5, func, "func called after 5 sec")reactor.addSystemEventTrigger('during', ‘FireworkEvent', Firework_CustomEventHandler)reactor.run()

Let’s create a custom self-esteem boosting event.

addSystemEventTrigger can be done

‘before’, ‘during’, or ‘after’ event.

Page 13: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

REACTOR BASICS

import sys, timefrom twisted.python import loglog.startLogging(sys.stdout)

def func(x):log.msg(str(x))now = time.localtime(time.time())log.msg(str(time.strftime("%y/%m/%d %H:%M:%S",now)))log.msg("Fire FireworkEvent after 3 seconds…")reactor.callLater(3, reactor.fireSystemEvent, ‘FireworkEvent')

def Firework_CustomEventHandler():now = time.localtime(time.time())log.msg(str(time.strftime("%y/%m/%d %H:%M:%S",now)))log.msg(“BABY YOU’RE A FIIIIIIIIREWOOOOOORK")reactor.stop()

now = time.localtime(time.time())log.msg(str(time.strftime("%y/%m/%d %H:%M:%S",now)))from twisted.internet import reactorreactor.callLater(5, func, "func called after 5 sec")reactor.addSystemEventTrigger('during', ‘FireworkEvent', Firework_CustomEventHandler)reactor.run()

$ python twist.py

2015-02-17 11:53:43-0500 [-] Log opened.

2015-02-17 11:53:43-0500 [-] 15/02/17 11:53:43

2015-02-17 11:53:48-0500 [-] func called after 5 sec

2015-02-17 11:53:48-0500 [-] 15/02/17 11:53:48

2015-02-17 11:53:48-0500 [-] Fire FireworkEvent after 3 seconds...

2015-02-17 11:53:51-0500 [-] 15/02/17 11:53:51

2015-02-17 11:53:51-0500 [-] BABY YOU'RE A FIIIIIIIIREWOOOOOORK

2015-02-17 11:53:51-0500 [-] Main loop terminated.

Page 14: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

REACTOR BASICS

Let’s back up for a second and make sure we understand what’s going on.

• Our callback code runs in the same thread as the Twisted loop.

• When our callbacks are running, the Twisted loop is not running. And vice versa.

• The reactor loop resumes when our callback returns.

Our code blocks the reactor loop so it should return asap.

Before we continue writing our TCP server, we need to learn about a couple of abstractions.

Page 15: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

TRANSPORT BASICS

The Transport abstraction is defined in twisted.internet.interfaces.ITransport.

A Twisted Transport represents a single connection that can send/receive data.

The Transport abstraction represents any such connection and handles the details of asynchronous I/O for whatever sort of connection it represents. The methods defined in Itransport are:

• write(data) – send some data.

• writeSequence(list_of_data) – send a sequence of data.

• loseConnection() – close connection.

• getPeer() – get remote address of other side of connection.

• getHost() – get address of this side of connection.

Page 16: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

TRANSPORT BASICS

You may have noticed that there are no methods for reading data. The Transport object will make a callback when it receives data – we don’t have to explicitly make it happen.

Also, note that these methods are really just suggestions. Remember, Twisted is in control, not us. So when we tell the Transport to write some data, we’re really asking it to write some data whenever it is able to.

Page 17: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

PROTOCOLS

The Protocol abstraction is defined in twisted.internet.interfaces.IProtocol.

Protocols implement protocols. This could be one of the built-in protocols in twisted.protocols.basic or one of your own design.

Strictly speaking, a Protocol instance implements the protocol for a single connection. This connection is represented by a Transport object.

So every connection requires its own Protocol instance (and therefore, Protocol is a good candidate for storing stateful information about the connection).

Page 18: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

PROTOCOLS

Methods of the IProtocol class include:

• dataReceived(data) – called whenever data is received (transport’s callback!)

• connectionLost(reason) – called when connection is shut down.

• makeConnection(transport) – associates transport with protocol instance to make connection.

• connectionMade() – called when a connection is made.

Page 19: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

PROTOCOL FACTORIES

The Protocol Factory object is defined in twisted.internet.interfaces.IProtocolFactory.

Protocol Factories simply create Protocol instances for each individual connection. Of interest is just one method:

• buildProtocol(addr): The buildProtocol method is supposed to return a new Protocol instance for the connection to addr. Twisted will call this method to establish Protocols for connections.

Page 20: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

SIMPLE TCP SERVER

from twisted.internet.protocol import Protocol, Factory

class Echo(Protocol): # reactor will call makeConnection with current transport instance.

def dataReceived(self, data): # when transport executes callback with data, just echo

self.transport.write(data)

f = Factory()f.protocol = Echo # f.buildProtocol() will create an instance of f.protocol

from twisted.internet import reactorreactor.listenTCP(9000, f) # listenTCP defined in IReactorTCP, which the default reactor inherits

reactor.run()

Page 21: Lecture 16 - Florida State Universitycarnahan/cis4930sp15/Lecture16_python.pdfTwisted has a basic logging mechanism defined in twisted.python.log. import sys from twisted.python import

SIMPLE TCP SERVER

from twisted.internet.protocol import Protocol, Factory

class Echo(Protocol):def dataReceived(self, data):

self.transport.write(data)

f = Factory()f.protocol = Echofrom twisted.internet import reactorreactor.listenTCP(9000, f) reactor.run()

Try “telnet localhost 9000”.

Anything you send will be echoed back to you.

The only thing we’re doing explicitly is running

the server. Everything that is executed from that

point forward is handled and scheduled by Twisted.


Recommended