Python telnetlib: surprising problem

2019-04-12 08:37发布

问题:

I am using the Python module telnetlib to create a telnet session (with a chess server), and I'm having an issue I really can't wrap my brain around. The following code works perfectly:

>>> f = login("my_server") #code for login(host) below.
>>> f.read_very_eager()

This spits out everything the server usually prints upon login. However, when I put it inside a function and then call it thus:

>>> def foo():
...   f = login("my_server")
...   return f.read_very_eager()
...
>>> foo()

I get nothing (the empty string). I can check that the login is performed properly, but for some reason I can't see the text. So where does it get swallowed?

Many thanks.

For completeness, here is login(host):

def login(host, handle="guest", password=""):
try:
    f = telnetlib.Telnet(host) #connect to host
except:
    raise Error("Could not connect to host")
f.read_until("login: ")
try:
    f.write(handle + "\n\r")
except:
    raise Error("Could not write username to host")
if handle == "guest":
    f.read_until(":\n\r")
else:
    f.read_until("password: ")
try:
    f.write(password + "\n\r")
except:
    raise Error("Could not write password to host")
return f

回答1:

The reason why this works when you try it out manually but not when in a function is because when you try it out manually, the server has enough time to react upon the login and send data back. When it's all in one function, you send the password to the server and never wait long enough for the server to reply.

If you prefer a (probably more correct) technical answer:

In file telnetlib.py (c:\python26\Lib\telnetlib.py on my Windows computer), function read_very_eager(self) calls self.sock_avail() Now, function sock_avail(self) does the following:

def sock_avail(self):
    """Test whether data is available on the socket."""
    return select.select([self], [], [], 0) == ([self], [], [])

What this does is really simple: if there is -anything- to read from our socket (the server has answered), it'll return True, otherwise it'll return False.

So, what read_very_eager(self) does is: check if there is anything available to read. If there is, then read from the socket, otherwise just return an empty string.

If you look at the code of read_some(self) you'll see that it doesn't check if there is any data available to read. It'll try reading till there is something available, which means that if the server takes for instance 100ms before answering you, it'll wait 100ms before returning the answer.



回答2:

I'm having the same trouble as you, unfortunately the combination of select.select, which I have in a while loop until I am able to read, and then calling read_some() does not work for me, still only reading 1% of the actual output. If I put a time.sleep(10) on before I read and do a read_very_eager() it seems to work...this is a very crude way of doing things but it does work..I wish there was a better answer and I wish I had more reputation points so I could respond to user387821 and see if he has any additional tips.