试图使 asyncio 与 telnetlib 一起工作
Posted
技术标签:
【中文标题】试图使 asyncio 与 telnetlib 一起工作【英文标题】:Trying to make asyncio working with telnetlib 【发布时间】:2021-02-24 18:35:46 【问题描述】:我很难让 asyncio 与 telnetlib 一起工作以询问某些硬件。
我想我显然不明白 asyncio 的工作方式,我完全迷失在这一切中。真的不清楚。
我的基本版本(同步)运行良好,但查询完整的设备列表实际上需要 6 个小时,并且大部分设备没有响应,因为它们无法访问。
由于 Asyncio 使我们能够并行化连接而无需等待每次超时触发,我想将我的代码转换为适当的异步代码,但没有成功。
这是我尝试过的:
import telnetlib
import time
import datetime
import asyncio
from env.fonctions import *
from env.variables import *
first_cmds = ['term length 0', \
'show run', \
'exit']
#create lists to iterate through
hosts = ['router-1', 'router-2', 'router-3', 'router-4', 'router-5']
async def main(hosts, user_rw_hw ,password_rw_hw, first_cmds):
class ContinueI(Exception):
pass
continue_i = ContinueI()
for host in hosts:
print(f'host | Trying to connect...')
try:
tn = await async_establish_telnet_connexion(user_rw_hw ,password_rw_hw, host, 23, 0.5, True)
except:
continue
print(f'host | Checking if equipment is not Nexus')
tn.write('show version'.encode('ascii') + b"\n")
sh_ver = await async_read_telnet_output(tn)
if 'Nexus' in sh_ver or 'NX-OS' in sh_ver or 'nexus' in sh_ver:
print(f'host | Equipment is Nexus, closing connection...')
tn.write('exit'.encode('ascii') + b"\n")
continue
tn.write(''.encode('ascii') + b"\n")
try:
for cmd in first_cmds:
tn.write(cmd.encode('ascii') + b"\n")
if not 'exit' in cmd:
response = await async_read_telnet_output(tn)
if '\r\n% Invalid' in response:
print(f'host | Commande "cmd" pas reconnue')
raise continue_i
else:
print(f'host | Commands are accepted')
except ContinueI:
tn.write(b"exit\n")
tn.write(b"exit\n")
print(f'host | Logout for command not recognized')
continue
if __name__ == "__main__":
try:
loop = asyncio.get_event_loop()
loop.set_debug(1)
loop.run_until_complete(main(hosts, user_rw_hw ,password_rw_hw, first_cmds))
except Exception as e:
pass
finally:
loop.close()
和功能:
async def async_read_telnet_output(tn, timeout=2, timestep=0.1):
timer = 0
data = b''
while timer <= timeout:
new_datas = tn.read_very_eager()
if len(new_datas) != 0:
timer = 0
data += new_datas
await asyncio.wait(timestep)
timer += timestep
return data.decode('utf-8')
async def async_establish_telnet_connexion(user_rw_hw, password_rw_hw, host, port=23, timeout=1, debug=False):
try:
tn = telnetlib.Telnet(host, port) # Here I don't know how to make it awaitable, if I put await before the IDE said that this method is not an awaitable, btw even if I put an awaitable like "asyncio.sleep" the behavior is still the same so it's not the only point bad
except:
if debug == True:
print(f"host | Telnet not responding.")
raise Exception
if debug == True:
print(f"host | Telnet is responding.")
response = loop.create_task(async_read_telnet_output(tn, 15))
if not 'Username:' in response and not 'login' in response:
if debug == True:
print(f"host | Don't see Username asked by equipment.")
raise Exception
else:
tn.write(user_rw_hw.encode('ascii') + b"\n")
if debug == True:
print(f"host | Username entered.")
try:
await tn.read_until(b"Password: ", timeout)
except:
if debug == True:
print(f"host | Don't see Password asked by equipment.")
raise Exception
finally:
tn.write(password_rw_hw.encode('ascii') + b"\n")
response = await async_read_telnet_output(tn, 10)
if '% Authentication failed' in response or 'Rejected' in response:
if debug == True:
print(f"host | Connection failed bad credentials.")
raise Exception
if debug == True:
print(f"host | Connection succeed waiting for commands.")
return tn
如果有人知道我失败的地方,我会很感激我被困了一个星期......阅读一些书籍和 youtube tutos 但没有任何帮助......
提前谢谢你!
【问题讨论】:
虽然它实际上并不能解决您的问题,但您可能需要阅读How does asyncio actually work?。代码必须是异步的,你不能仅仅await
一个同步函数并期望它变成并发的。使用线程而不是协程可能更容易解决您的问题。
好的,我马上看,谢谢MisterMiyagi :)
我现在明白你的意思@MisterMiyagi,我在想,由于 telnet 有时正在等待答案,它应该自动“异步”,但现在我明白你的意思了,我会仔细看看这点。事实上,我认为这是可能的,因为我的函数“async_read_telnet_output”使用的是 asyncio.sleep 方法,如果我理解得很好,那么我会看到重构我的代码,如果是不兼容的 telnetlib,我可以看看套接字库是否是“异步的”并从头开始创建一个新的 telnet 客户端。再次感谢!
【参考方案1】:
对于那些登陆这里的人......我找到了 https://pypi.org/project/asynctelnet/
快速示例:
客户:
import anyio, asynctelnet
async def shell(tcp):
async with asynctelnet.TelnetClient(tcp, client=True) as stream:
while True:
# read stream until '?' mark is found
outp = await stream.receive(1024)
if not outp:
# End of File
break
elif '?' in outp:
# reply all questions with 'y'.
await stream.send('y')
# display all server output
print(outp, flush=True)
# EOF
print()
async def main():
async with await connect_tcp('localhost', 56023) as client:
await shell(client)
anyio.run(main)
服务器:
import anyio, asynctelnet
async def shell(tcp):
async with asynctelnet.TelnetServer(tcp) as stream:
# this will fail if no charset has been negotiated
await stream.send('\r\nWould you like to play a game? ')
inp = await reader.receive(1)
if inp:
await stream.echo(inp)
await stream.send('\r\nThey say the only way to win '
'is to not play at all.\r\n')
async def main():
listener = await anyio.create_tcp_listener(local_port=56023)
await listener.serve(shell)
anyio.run(main)
这个库仍然有一些错误。所以目前的状态是“如果你想使用它,请准备好编写一些错误解决方法”。
【讨论】:
以上是关于试图使 asyncio 与 telnetlib 一起工作的主要内容,如果未能解决你的问题,请参考以下文章