-2

I know a similar question has been asked here, but I am still battling with the following issue:

I am using putty as a telnet client and am using Win10. The code is given below. When I start the reactor and then connect a client, I get a response after each character is typed which is printed using the dataReceived function. However I can never seem to get the function lineReceived() to fire. I also tried a simple chat server example which worked fine using the lineReceived() function (and that example had no dataReceived() function. I tried commenting out dataReceived(), thinking perhaps it was masking out lineReceived().

In the code below, I cannot get lineReceived() to fire , only dataReceived() fires after each character is typed.

#! C:/Python37/python.exe

from twisted.internet import reactor
from twisted.internet.protocol import Factory, Protocol
from datetime import datetime, tzinfo, timedelta
from twisted.protocols.basic import LineReceiver


class Echo(Protocol):
    def dataReceived(self, data):
        self.transport.write(data)


class LineReceiver(Protocol):

    print("Starting.......")
    delimiter = "\n"
    TIMEOUT = 300  # Client timeout period in seconds

    def timeOut(self):
        print("Client: %s. %s" % (self.addr, "Connection Timed out"))
        self.transport.loseConnection()

    def lineLengthExceeded(self, line):
        return self.transport.loseConnection()

    def connectionMade(self):
        print("Connected......")
        self.transport.write(b"hell...")

        self.timeout = reactor.callLater(
            self.TIMEOUT, self.timeOut
        )  # start client timeout timer
        self.addr = self.transport.getPeer().host
        addr = self.addr
        self.addr_test = self.transport.getPeer().host
        self.factory.NUM_CLIENTS += 1

    def connectionLost(self, reason):
        print("Lost.......")
        # self.sendMsg("- %s left." % self.name)
        self.transport.write(b"a client left")
        self.factory.NUM_CLIENTS -= 1
        print("Client disconnected: - " + str(self.addr))
        print("Number of connections = %s" % self.factory.NUM_CLIENTS)

    # def dataReceived(self, data): # this runs a few times after an initial connection

    # self.transport.write(b"you typed: " + data +b"\n" + b"\r")
    # print(data) # prints to log file with byte order marks

    def lineReceived(self, line):
        self.sendLine(b"Welcome, %s!" % (name,))
        self.transport.write(b"line rx function...")


class DataFactory(Factory):
    protocol = LineReceiver
    NUM_CLIENTS = 0


def main():
    print("Started...Listening for incoming connections.")


if __name__ == "__main__":
    main()
    reactor.listenTCP(10003, DataFactory())
    reactor.run()
notorious.no
  • 4,919
  • 3
  • 20
  • 34
Russell
  • 99
  • 7
  • 1
    Please format your code correctly. Python code does not work if indented incorrectly. – wovano Aug 25 '20 at 18:40
  • Could you be more explicit? I am not getting any indent errors. – Russell Aug 25 '20 at 20:11
  • 1
    The code in the question is indented so that it will not parse. Your methods are not indented beneath your classes. – Jean-Paul Calderone Aug 26 '20 at 00:43
  • 1
    Please look at the code in the question and tell me if you think this is valid Python code. If you really think so, copy-paste it into a `.py` file and try to run it. If you don't get an `IndentationError` you are running different code than posted in the question. – wovano Aug 26 '20 at 05:32
  • The original code was edited so that it formats correctly. https://stackoverflow.com/editing-help#syntax-highlighting – notorious.no Aug 26 '20 at 16:09

1 Answers1

0

You overwrote LineReceiver with your own Protocol subclass, which does not have a lineReceived() method. You just gave me a good reason for using the module path as a namespace instead of importing a specific object :D

from twisted.protocols import basic
from twisted.internet import endpoints, protocol, reactor

class LnRcv(basic.LineReceiver):
    def lineReceived(self, line):
        print(line)

class DataFactory(protocol.Factory):
    protocol = LnRcv

server = endpoints.TCP4ServerEndpoint(reactor, 10003)
server.listen(DataFactory())
reactor.run()

Update

I had some spare time to fix your code. You have string/bytes mismatching all over and unreferenced objects that were not in your original code. Here's an example that should work and give you a base to off of.

from uuid import uuid4

from twisted.internet import reactor
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.internet.protocol import Factory, Protocol
from twisted.protocols.basic import LineReceiver


class LnRcv(LineReceiver):
    # Client timeout period in seconds
    TIMEOUT = 10

    def timeOut(self):
       print ("Client: %s. %s" % (self.addr, 'Connection Timed out' ))
       self.transport.loseConnection()

    def connectionMade(self):
        self.factory.NUM_CLIENTS += 1
        print(f"Connected......number of connections = {self.factory.NUM_CLIENTS}")
        peer = self.transport.getPeer()
        self.addr = f"{peer.host}:{peer.port}"
        self.name = uuid4().hex[:9].upper()
        self.transport.write(f"Hello! I temporarily set your ID to {self.name}. What is your name? ".encode("utf8"))
        # Start client timeout timer
        self.timeout = reactor.callLater(self.TIMEOUT, self.timeOut)

    def connectionLost(self, reason):
        self.factory.NUM_CLIENTS -= 1
        print(f"- {self.name} left because:\n{reason.getErrorMessage()}")
        print(f"- Client disconnected: - {self.addr}")
        print(f"- Number of connections = {self.factory.NUM_CLIENTS}")

    def lineReceived(self, line):
         self.sendLine(f"Welcome, {line.decode('utf8')}!".encode("utf8"))


class DataFactory(Factory):
    protocol = LnRcv
    NUM_CLIENTS = 0


def main():
    print("Started...Listening for incoming connections.")
    server = TCP4ServerEndpoint(reactor, 10003)
    server.listen(DataFactory())
    reactor.run()


if __name__ == "__main__":
    main()
notorious.no
  • 4,919
  • 3
  • 20
  • 34
  • Note that pyflakes will immediately tell you about this mistake so I don't know if it's a compelling reason to use the module import pattern. :) Contrariwise, pyflakes (nor any other static checker, essentially) can tell you if you're trying to use an attribute of a module that doesn't exist. – Jean-Paul Calderone Aug 26 '20 at 00:45
  • I could've sworn `pylint` yells at in this scenario. I'm not even sure these days. My `pylintrc` file ignore a lot of stuff ;B – notorious.no Aug 26 '20 at 03:23
  • Note that there are [more reasons](https://stackoverflow.com/questions/9916878/importing-modules-in-python-best-practice) to avoid the `from module import something` style of importing. – wovano Aug 26 '20 at 05:45
  • Thanks for all the replies. So you mean my choice of class name class LineReceiver(Protocol): has basically overwritten the parent lineReceived ? Right you are about pyflakes - it shows redefinition of unused LineReceiver from line 10 – Russell Aug 26 '20 at 07:56
  • You example is great thanks, I ran it fine. But I'm still just battling with the specifics of what exactly to modify in my original file to use both lineReceived and dataReceived. If I comment out dataReceived, then lineReceived works. I can submit my changed code if you like - could you perhaps advise?, many thanks – Russell Aug 26 '20 at 09:25
  • @wovano There don't seem to be a lot of *reasons* on that post, though there are a lot of opinions. :) – Jean-Paul Calderone Aug 26 '20 at 13:36
  • @Russell `LineReceiver` obj is a subclass of `Protocol` and overwrites `dataReceived()` to execute `lineReceived()`, so if you overwrite it then it is expected that `lineRecieved()` won't work. Why do you need both `lineReceived` and `dataReceived` to run? – notorious.no Aug 26 '20 at 14:33
  • Hi - I probably don't need both, I'm just experimenting on a listener and was running a few tests. But that does help explain what I had thought, many thanks. R – Russell Aug 26 '20 at 19:28