Created
April 29, 2013 22:53
-
-
Save smartkiwi/5485455 to your computer and use it in GitHub Desktop.
PA4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# 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