Contents
Twisted
Twisted is an event-driven networking engine written in Python and licensed under the open source MIT license.
The reactor pattern has an event loop and is event driven. The following projects use the reactor pattern:
- twisted
- netty
- nodejs
- Spring with version equal or higher than 5 (reactive , webflux)
Install from source
Test installation
Slackbuild
1 su
2 cd /tmp
3 wget http://slackbuilds.org/slackbuilds/14.1/python/python-twisted.tar.gz
4 tar xvzf python-twisted.tar.gz
5 cd python-twisted
6 wget https://pypi.python.org/packages/source/T/Twisted/Twisted-13.2.0.tar.bz2
7 ./python-twisted.SlackBuild
8 installpkg /tmp/python-twisted-13.2.0-x86_64-1_SBo.tgz
Slackware64 14: python-twisted-13.2.0-x86_64-1_SBo.tgz
Echo server
1 from twisted.internet import protocol, reactor
2
3 class Echo(protocol.Protocol):
4 def dataReceived(self, data):
5 self.transport.write(data)
6
7 def connectionMade(self):
8 print('Connection made')
9
10 def connectionLost(self,reason):
11 print('Connection lost')
12 class EchoFactory(protocol.Factory):
13 def buildProtocol(self, addr):
14 return Echo()
15
16 if __name__=='__main__':
17 reactor.listenTCP(1234, EchoFactory())
18 reactor.run()
Echo client
1 import threading
2 import time
3 import socket
4
5 class Client (threading.Thread):
6 def __init__(self):
7 threading.Thread.__init__(self) #required
8
9 def run(self):
10 for x in range(1,100):
11 HOST = 'localhost'
12 PORT = 1234
13 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
14 print('connecting...')
15 s.connect((HOST, PORT))
16 print('sending config...')
17 s.send('test')
18 s.close()
19 print('complete')
20
21 if __name__=='__main__':
22
23 clients=[]
24 for x in range(1,100):
25 clients.append( Client() )
26
27 for c in clients:
28 c.start()
Sample web server
1 # from https://twistedmatrix.com/trac/
2 from twisted.web import server, resource
3 from twisted.internet import reactor, endpoints
4
5 class Counter(resource.Resource):
6 isLeaf = True
7 numberRequests = 0
8
9 def render_GET(self, request):
10 self.numberRequests += 1
11 request.setHeader(b"content-type", b"text/plain")
12 content = u"I am request #{}\n".format(self.numberRequests)
13 return content.encode("ascii")
14
15 endpoints.serverFromString(reactor, "tcp:8080").listen(server.Site(Counter()))
16 reactor.run()
- apt-get instal apache2-utils
- apt-get install nginx
- apt-get install links
/etc/nginx/conf.d/load-balancer.conf
upstream backend {
server 172.28.128.4:8080;
server 172.28.128.3:8080;
server 172.28.128.6:8080;
}
server {
listen 8080;
location / {
proxy_pass http://backend;
}
}
twistedtest.py
1 from twisted.web import server
2 from twisted.web import resource
3 from twisted.internet import reactor
4 from twisted.internet import endpoints
5 import time
6 import sys
7
8 class Handler(resource.Resource):
9 isLeaf = True
10 numberRequests = 0
11
12 def render_GET(self, request):
13 self.numberRequests += 1
14 time.sleep(0.1) # wait 100 ms
15 request.setHeader(b"content-type", b"text/plain")
16 content = u"I am request #{}\n".format(self.numberRequests)
17 return content.encode("ascii")
18
19 if __name__=='__main__':
20 port = sys.argv[1]
21 print('Listening on port %s'%(port))
22 endpoints.serverFromString(reactor,"tcp:%s" %(port) ).listen(server.Site(Handler()))
23 reactor.run()
twistedclient.py
1 import threading
2 import urllib2
3 import time
4 import sys
5
6 class Client(threading.Thread):
7 def __init__(self,urls,nrReqs):
8 threading.Thread.__init__(self) #required
9 self.urls=urls
10 self.nrReqs=nrReqs
11 self.count=0
12 def run(self):
13 loop=True
14 urlIdx=0
15 while loop:
16 url=urls[urlIdx]
17 conn=urllib2.urlopen(url)
18 resp=conn.read()
19 if self.count < self.nrReqs-1:
20 self.count+=1
21 urlIdx+=1
22 if urlIdx>=len(urls):
23 urlIdx=0
24 else:
25 loop=False
26
27 if __name__=='__main__':
28 if len(sys.argv) == 4:
29 nrUrlsToUse = int(sys.argv[1])
30 nrClients=int(sys.argv[2])
31 nrReqs=int(sys.argv[3])
32
33 start = time.time()
34 urls=['http://localhost:8080/','http://localhost:8081/','http://localhost:8082/','http://localhost:8083/','http://localhost:8084/','http://localhost:8085/','http://localhost:8086/','http://localhost:8087/','http://localhost:8088/','http://localhost:8089/','http://localhost:8090/','http://localhost:8091/','http://localhost:8092/','http://localhost:8093/','http://localhost:8094/','http://localhost:8095/','http://localhost:8096/','http://localhost:8097/','http://localhost:8098/','http://localhost:8099/']
35
36 if nrUrlsToUse<len(urls):
37 urls = urls[0:nrUrlsToUse]
38
39
40 clients=[]
41
42 for client in range(0,nrClients):
43 c = Client(urls,nrReqs)
44 clients.append( c )
45 c.start()
46
47 for client in clients:
48 client.join()
49
50 end = time.time()
51 delta = end-start
52 totalRequests = nrReqs*nrClients
53 reqPerSec = totalRequests/delta
54 print('Test time: %d Total requests:%d ReqsPerSec:%f TotalURLs: %d'%(delta,totalRequests,reqPerSec,len(urls)))
55 else:
56 print('Usage: twistedclient.py <nrUrlsToUse> <nrClients> <nrReqs>')
