socket programming strategy

Richie Hindle richie at entrian.com
Wed Jan 22 10:36:40 EST 2003


[Andrew Bennetts]
> An example of doing this in Twisted

[Richie]
> This is a wonderful example

...except for two bugs.  8-)

It falls over when you feed it lots of lines at once (eg. by telnetting
to it and pasting a bunch of lines into the terminal) for two reasons:

 o It deletes completed jobs from the wrong end of the stack.
 o The callback can be called with no work left, so it needs to check
   that the stack isn't empty.

Here's a fixed version, with my edits marked with 'RJH':

----------------------------------------------------------------------

from twisted.protocols import basic
from twisted.internet import reactor
from twisted.internet.protocol import ServerFactory

class LongMultiplicationProtocol(basic.LineReceiver):
    """A protocol for doing long multiplications.

    It receives a list of numbers (seperated by whitespace) on a line, and
    writes back the answer.  The answer is calculated in chunks, so no one
    calculation should block for long enough to matter.
    """
    def connectionMade(self):
        self.workQueue = []
        
    def lineReceived(self, line):
        try:
            numbers = map(long, line.split())
        except ValueError:
            self.sendLine('Error.')
            return

        if len(numbers) <= 1:
            self.sendLine('Error.')
            return

        self.workQueue.append(numbers)
        reactor.callLater(0, self.calcChunk)

    def calcChunk(self):
        # RJH:
        # Make sure there's some work left; when multiple lines are received
        # while processing is going on, multiple calls to reactor.callLater()
        # can happen between calls to calcChunk().
        if self.workQueue:
            # Get the first bit of work off the queue
            work = self.workQueue[0]
    
            # Do a chunk of work: [a, b, c, ...] -> [a*b, c, ...]
            work[:2] = [work[0] * work[1]]
    
            # If this piece of work now has only one element, send it.
            if len(work) == 1:
                self.sendLine(str(work[0]))
                del self.workQueue[0]  # RJH: Not `self.workQueue.pop()`!
            
            # Schedule this function to do more work, if there's still work
            # to be done.
            if self.workQueue:
                reactor.callLater(0, self.calcChunk)


class LongMultiplicationFactory(ServerFactory):
    protocol = LongMultiplicationProtocol


if __name__ == '__main__':
    from twisted.python import log
    import sys
    log.startLogging(sys.stdout)
    reactor.listenTCP(1234, LongMultiplicationFactory())
    reactor.run()

----------------------------------------------------------------------

I-know-it's-only-an-example-but-I-can't-help-myself-ly yrs,

-- 
Richie Hindle
richie at entrian.com




More information about the Python-list mailing list