1
votes

I am currently trying work on a project using Twisted Python, my problem specifically is my attempt to gain user input whilst also listening for connections using listenTCP(). I looked up the problem originally and found that stdio.StandardIO seems the most efficient way of doing so since I am already using Twisted. I have also seen the code examples found on twisted matrix, stdin.py and also stdiodemo.py however I am struggling with how to apply to example code to my specific problem given I need to read from the socket and also gather user input while performing tcp tasks.

The project I am working on is much larger however the small example code illustrates what I am trying to do and isolates the problem I am having. Any help in solving my problem is really appreciated.

Server.py

from twisted.internet.protocol import Factory
from twisted.protocols import basic
from twisted.internet import reactor, protocol, stdio
from Tkinter import *
import os, sys

class ServerProtocol(protocol.Protocol):
    def __init__(self, factory):
        self.factory = factory
        stdio.StandardIO(self)

    def connectionMade(self):
        self.factory.numConnections += 1
        self.factory.clients.append(self)

    def dataReceived(self, data):
        try:
            print 'receiving data'
            print data
        except Exception, e:
            print e

    def connectionLost(self, reason):
        self.factory.numConnections -= 1
        self.factory.clients.remove(self)

class ServerFactory(Factory):
    numConnections = 0
    def buildProtocol(self, addr):
        return ServerProtocol(self)

class StdioCommandLine(basic.LineReceiver):
    from os import linesep as delimiter
    def connectionMade(self):
        self.transport.write('>>> ')
    def lineReceived(self, line):
        self.sendLine('Echo: ' + line)
        self.transport.write('>>> ')

reactor.listenTCP(9001, ServerFactory())
stdio.StandardIO(StdioCommandLine())
reactor.run()

Client.py

from twisted.internet import reactor, protocol
import os, time, sys
import argparse

class MessageClientProtocol(protocol.Protocol):

    def __init__(self, factory):
        self.factory = factory

    def connectionMade(self):
        self.sendMessage()

    def sendMessage(self):
        print 'sending message'
        try:
            self.transport.write('hello world')
        except e as Exception:
            print e

    def dataReceived(self, data):
        print 'received: ', data
        self.sendMessage()

class MessageClientFactory(protocol.ClientFactory):

    def __init__(self, message):
        self.message = message

    def buildProtocol(self, addr):
        return MessageClientProtocol(self)

    def clientConnectionFailed(self, connector, reason):
        print 'Connection Failed: ', reason.getErrorMessage()
        reactor.stop()

    def clientConnectionLost(self, connector, reason):
        print 'Connection Lost: ', reason.getErrorMessage()

reactor.connectTCP('192.168.1.70', 9001, MessageClientFactory('hello world - client'))
reactor.run()

At the moment the above code is returning an Unhanded Error as follows. This demonstrates me using stdin, then it returning the data to stdout and a client the connects causing the error:

python Server.py

>>> hello

Echo: hello

>>> Unhandled Error Traceback (most recent call last):

File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/twisted/python/log.py", line 84, in callWithContext

return context.call({ILogContext: newCtx}, func, *args, **kw)

File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/twisted/python/context.py", line 118, in callWithContext return self.currentContext().callWithContext(ctx, func, *args, **kw)

File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/twisted/python/context.py", line 81, in callWithContext

return func(*args,**kw)

File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/twisted/internet/selectreactor.py", line 149, in _doReadOrWrite

why = getattr(selectable, method)()

--- exception caught here ---

File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/twisted/internet/tcp.py", line 1067, in doRead
protocol = s

1
The end of your traceback seems to be cut off. - Manuel Jacob
Sorry protocol = s is the last line, however that is the total error that is displayed. Just to add, after the client connects to the server the error above is displayed and then I can continue to provide user input. Any further client connections also give the same error. - KernelMode
That's strange. Looking at the code in tcp.py, line 1067, the line should be protocol = self.factory.buildProtocol(self._buildAddr(addr)). - Manuel Jacob
Mine is also reading the same i.e: protocol = self.factory.buildProtocol(self._buildAddr(addr)). I have double checked the error message and the formatting had got messed up on the last couple of lines prior to that which I have corrected. - KernelMode
I tried to reproduce the problem locally and on my machine it shows the full traceback. I'll write an answer including the traceback. - Manuel Jacob

1 Answers

0
votes

The traceback you provided seems to be cut off. I tried to run the code on my machine and it shows this traceback:

Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/twisted/python/log.py", line 84, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File "/usr/lib/python2.7/site-packages/twisted/python/context.py", line 118, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File "/usr/lib/python2.7/site-packages/twisted/python/context.py", line 81, in callWithContext
    return func(*args,**kw)
  File "/usr/lib/python2.7/site-packages/twisted/internet/posixbase.py", line 597, in _doReadOrWrite
    why = selectable.doRead()
--- <exception caught here> ---
  File "/usr/lib/python2.7/site-packages/twisted/internet/tcp.py", line 1067, in doRead
    protocol = self.factory.buildProtocol(self._buildAddr(addr))
  File "Server.py", line 30, in buildProtocol
    return ServerProtocol(self)
  File "Server.py", line 10, in __init__
    stdio.StandardIO(self)
  File "/usr/lib/python2.7/site-packages/twisted/internet/_posixstdio.py", line 42, in __init__
    self.protocol.makeConnection(self)
  File "/usr/lib/python2.7/site-packages/twisted/internet/protocol.py", line 490, in makeConnection
    self.connectionMade()
  File "Server.py", line 14, in connectionMade
    self.factory.clients.append(self)
exceptions.AttributeError: ServerFactory instance has no attribute 'clients'

As can be easily seen with the full traceback, the factory is missing the client attribute. This can be fixed e.g. by adding this to your ServerFactory class:

def __init__(self):
    self.clients = []