Skip to content

Instantly share code, notes, and snippets.

@smartkiwi
Created April 29, 2013 22:53
Show Gist options
  • Save smartkiwi/5485455 to your computer and use it in GitHub Desktop.
Save smartkiwi/5485455 to your computer and use it in GitHub Desktop.
PA4
#
# PA 4
#
# based on https://class.coursera.org/posa-001/forum/thread?thread_id=1149
# changes
# + handler run on line sent by client
# + original implementation with endopoint doesn't run on Windows without installing addiotional libs - implemented using reactor.listenTCP
# + added logging
#
#
# Python version 2.7.2, and Twisted version 12.1.0, tested on Mac OS X and Windows platforms
#
#
import sys
from twisted.internet import reactor, threads, protocol
import thread
import time
from twisted.protocols.basic import LineReceiver
from twisted.python import log
class EchoServerHandler(LineReceiver):
'''Protocol which echoes back whatever it receives separate line from client.'''
def connectionLost(self, reason):
'''called when a connection is shut down.'''
print "Closed connection to ",self.transport.getPeer(), " Reason: ",reason
def connectionMade(self):
'''This method overrides the t.i.BaseProtocol.connectionMade
method. It is called when a connection has been made.
For a server, this is when the accept() socket API call
stops blocking and a socket has been received.
'''
print "Incoming connection detected from: %s [thread %s]" % (self.transport.getPeer(),thread.get_ident())
def lineReceived(self, data):
'''This method overrides the LineReceiver.lineReceived
method. It is called when the Protocol receives line of data from client
'''
log.msg("data received %s bytes: %s [thread %s]" % (len(data),data,thread.get_ident()))
deferred = threads.deferToThread(self.processEchoData, data)
deferred.addCallback(self.sendProcessedDataBackToClient)
def processEchoData(self, x):
'''This function will run in a separate thread created by Twisted framework
We do not want to write back to the client socket in
this thread. Writing back to the client socket
should take place in the same thread as the
reactor which handles the socket connections.'''
x = x.rstrip()
x2 = "%s (len(%s)) [processed in thread: %d]\n" % (x, len(x), thread.get_ident())
log.msg(x2)
# Sleep here to simulate doing some blocking work.
time.sleep(3)
return x2
def sendProcessedDataBackToClient(self, x):
'''When the Deferred completes, and has data available,
then this function will be called. This function
will be called in the same thread as the reactor.
'''
self.transport.write(x)
class EchoServerFactory(protocol.Factory):
'''Factory object which creates new EchoServerHandler
protocol objects.
'''
def buildProtocol(self, addr):
log.msg("EchoServerFactory %s [thread: %s]" % (addr,thread.get_ident()))
return EchoServerHandler()
if __name__=='__main__':
log.startLogging(sys.stdout)
listenPort = 5555
print "Listening for new connection on port ",listenPort
# We create an reactor and configure it to listen to port [listenPort] for TCP
# connections.
# We register an EchoServerFactory() with this reactor
# Each time a new client connects to TCP port 5555, the EchoServerFactory
# will be called to create a new EchoServerHandler instance.
#
# This is the "Acceptor" part of the Acceptor-Connector Pattern.
reactor.listenTCP(listenPort, EchoServerFactory())
# threadpool thread limit
reactor.suggestThreadPoolSize(10)
# Start the reactor loop. The reactor will keep listening for incoming
# connections on port 5555.
# This is the Reactor pattern.
reactor.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment