2

I am having a similar problem to this poster:

Python telnetlib: surprising problem

Note the response and my response below it.

Essentially telnetlib is not letting me read an entire response when calling any of the read functions.

when calling telnet.read_very_eager() after using select.select([telnetobject],[],[]) in a while loop to make sure reading is available, the only thing I will get are a few characters. The only solution so far I am able to come up with is using time.sleep() but it is too crude of a solution and am looking for something that fits better. Any help appreciated...

Community
  • 1
  • 1
tSs
  • 125
  • 3
  • 9

3 Answers3

0

I had the same problem, I think, and I hope this information will help. In my case, I am connecting to the mel and python ports in Maya, so I have no idea if this experience will be useful to you and your situation.

  • This answer showed me that I didn't need Telnet/telnetlib at all for the I/O I was trying to do, and recommended asynchat.

  • It turned out not all output that appeared on the server side was available for the client to read. I had no idea that was a thing that could happen until I used asynchat as a second opinion and saw I still wasn't receiving the output from "print 'Complete Command'" no matter how I sent it. (I was trying to write "print 'Complete Command'" and read the result to know when my previous command had completed.)

I ended up calling mel's warning command, which does produce client-readable output. Sending innocent data as a warning is pretty distasteful, but fortunately this is for an internal tool.

  • telnetlib doesn't seem to queue writes. Thus my plan to send two commands back to back (the real command, then the "Command Complete" announcement) doesn't always work. Thus it seems like reading telnetlib output is only workable if you know exactly the output you want to read_until(), or you're willing to sleep until you suspect the output is done. However asynchat.push() definitely queues writes as expected.

A sample, to be taken with a huge grain of salt as I'm still figuring this out :

class mayaClient(asynchat.async_chat) :


... 

def __init__(self, sock, clientType):

    asynchat.async_chat.__init__(self, sock=sock)

    self.clientType = clientType
    self.ibuffer = []
    self.obuffer = ""
    self.set_terminator("\r\n")
    self.cumulativeResponse = ""


@classmethod
def withSocket(cls, host, clientType, log) :

    melSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    portNumber = cls.MEL_PORT_NUMBER if clientType == cls.MEL else cls.PYTHON_PORT_NUMBER
    melSocket.connect((host, portNumber))   
    return cls(melSocket, clientType, log)


#############################################################
# pushAndWait
#############################################################
def pushAndWait(self, command, timeout=60) :
    """
    ACTION:     Push a command and a "command complete" indicator
                If command completed, return number of milliseconds it took
                If command timed out without completing, return -1

    INPUT:      command as string
                description (optional) as string for more informative logging
                timeout in seconds as int after which to give up

    OUTPUT:     X milliseconds if command completed
                -1 if not

    """

    self.found_terminator()

    incrementToSleep = .001

    self.push("%s\r\n"%command)

    responseToSeek = "Command Complete"
    self.push('Whatever command is going to create readable output for %s`); \r\n'%responseToSeek)

    timeSlept = 0
    while responseToSeek not in self.currentBufferString() and timeSlept < timeout :
        self.read()
        timeSlept += incrementToSleep
        time.sleep(incrementToSleep)

    if responseToSeek in self.currentBufferString() :
        return timeSlept

    return -1


#############################################################
# read
#############################################################
def read(self) :
    """
    ACTION:     Reads the current available output
                and stores it in buffer

    """

    try :

        self.collect_incoming_data(self.recv(1024))

    except Exception, e :

        # Don't worry about it -- just means there's nothing to read
        #
        pass


#############################################################
# currentBuffer
#############################################################
def currentBuffer(self) :

    return self.ibuffer


#############################################################
# currentBufferString
#############################################################
def currentBufferString(self) :

    return "".join(self.ibuffer)


#############################################################
# collect_incoming_data
#############################################################
def collect_incoming_data(self, data):
    """Buffer the data"""

    self.ibuffer.append(data)   


#############################################################
# found_terminator
#############################################################
def found_terminator(self):

    print "Clearing --%s...-- from buffer"%self.currentBufferString()[0:20]
    self.ibuffer = []
Community
  • 1
  • 1
AteYourLembas
  • 303
  • 3
  • 12
0

Late to the party but this is doable with telnetlib. Below will read all lines until there is nothing left. timeout=0.1 adds some time for the response to arrive.

try:
    while True:             # read until we stop
        message = session.read_until(b'\n', timeout=0.1)
        if message == b'':  # check if there was no data to read
            break           # now we stop
        print(message)      # print message if not stopped
except EOFError:            # If connection was closed
    print('connection closed')

Or if you always want to wait for the response:

try:
    message = session.read_until(b'\n') # Will not timeout until you have response
    print(message)
    while True:             # read until we stop
        message = session.read_until(b'\n', timeout=0.1)
        if message == b'':  # check if there was no data to read
            break           # now we stop
        print(message)      # print message if not stopped
except EOFError:            # If connection was closed
    print('connection closed')
uranibaba
  • 712
  • 1
  • 13
  • 30
  • 1
    I see the point here to read output line by line. However what do you do if last line does not end with cr/lf? E.g. the telnet device may output a prompt and the prompt normally does not terminate with cr/lf. – Wör Du Schnaffzig Aug 16 '21 at 13:14
  • @avans I believe the program breaks if that happens. – uranibaba Aug 23 '22 at 19:17
0

I'm no expert on telnetlib, but I was recently experiencing the same thing. I played around with delays with time.sleep(), didn't really help. I tried closing and reopening the connection, that just didn't work hardly at all. What DID appear to work was calling telnet.interact(), then it seems to work perfectly. The code is 'interacting' with the telnet as a dumb telnet client does. So it appears. I'm writing a script to interact with a cognex barcode scanner for fun, and was just dealing with this it. It was reading the last barcode message each time, sometimes the latest and the last together. I was using read_until(b'\r\n',timeout = 0.1) and also read_eager(). Then I did that with read_until(b'\r\n') and it works great. night and day.

James
  • 11
  • 1