Python telnet 读取问题

Posted

技术标签:

【中文标题】Python telnet 读取问题【英文标题】:Python telnet read issue 【发布时间】:2018-03-30 06:09:32 【问题描述】:

我试图从一个不发送结束行或特殊字符的 telnet 服务器读取,以告诉 python telnet 客户端读取应该完成。然后将此数据发送到 tkinter 文本输入小部件,我希望它在其中不断更新从 telnet 服务器发送的新数据。存在的问题是我无法找到一种“不阻塞循环”的方法来从 telnet 服务器读取。谢谢

  def Telnet_Client(self):
    HOST = self.TelnetHostIP
    tn = telnetlib.Telnet(HOST)
    tn.write("s")
    tnrecv = tn.read_until(">", timeout=1)
    self.R.insert(tk.END, tnrecv)
    tn.close()

我使用了 read_some() 但我没有获得所有数据,并且 read_until(">", timeout=1) 会阻止代码,因为它永远不会得到结束行或停止读取的命令

【问题讨论】:

为什么不使用线程? 但是如何停止永无止境的读取过程? 如果读取在后台线程上,您不需要需要停止读取;这就是使用线程的全部意义——线程可以阻塞直到有东西要读取,而你的其他线程继续运行。 但是,从后台线程与 tkinter GUI 对话是不可能的,而且解决方法有点麻烦,所以它不像听起来那么容易完全 哇,这么多。我没想到会这么复杂。我打算切换到 python 3,但我遇到了 telnetlib 问题,所以现在我想要更改为 python 3 【参考方案1】:

这个问题的传统解决方案是产生一个后台线程来与套接字对话。该后台线程可以阻止读取,并且不会影响任何其他线程。但是,这有一个问题:tkinter 不是线程安全的,尝试从后台线程更新您的Entry 小部件将失败。 (根据您的平台,它可能会崩溃、阻止程序,或者最糟糕的是,间歇性工作并导致大量神秘错误。)

您可以搜索一些解决方法,但都不是很好。

基本思想是让后台线程向主线程发送消息——例如,通过将消息发布到主线程可以检查的queue.Queue(使用get(block=False))。但是,在您移动鼠标时,每次通过事件循环进行检查可能过于频繁,但在您空闲时却不够频繁 - 如果您要求 tkinter 每 N 秒触发一次检查,这可能会使笔记本电脑无法运行睡觉。此外,做到这一点并不完全困难,但也不是微不足道的。

曾经有一个很好的库将这一切尽可能地包装起来,称为mtTkinter,但它很久以前就被废弃了。几年前我ported it to Python 3,但最终没有使用它,因此该版本也被有效地放弃了。它可能会起作用,但我没有做出任何承诺。

这个解决方案的优点是它非常简单:import mttkinter as tkinter,添加一个threading.Thread(target=telnet_loop),再做几个小改动,你就完成了……如果它有效的话。


更现代的解决方案是使用asyncio(或像 Twisted 这样的前身或像 Curio 这样的竞争对手)。

您可以从 Tkinter 事件循环中驱动 asyncio 循环,它比任何线程解决方法都干净得多。 A 有现成的库可以为您完成。 (我不知道现在的情况,但我用的是几年前原来的asyncio-tkinter。)

唯一的问题是您不能使用telnetlib,因为它不是为asyncio 设计的。但几乎可以肯定还有更现代的 Telnet 库。 (通过快速搜索,我找到了telnetlib3,看起来很有希望,但我知道的不够多,无法推荐它。)

当然,此解决方案需要重写您的大部分网络代码——但您没有太多代码,而且它无法正常工作,所以这似乎不是一个太大的悲剧。与此同时,您的 tkinter 代码应该只需要进行一行更改。

【讨论】:

以上是关于Python telnet 读取问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 Python 检查 Telnet 是不是仍然连接

使用 Scapy python 识别 telnet 协议

python telnet

输入两个登录密码的Python telnet脚本?

pythontelnet批量连接脚本怎么能多个不同网段连接

使用 python 中的 telnet 检查远程主机是不是已启动