我试图从一个不发送结束行或特殊字符的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)会阻止代码,因为它永远不会得到一个结束行或命令来停止读取
答案 0 :(得分: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
循环,它比任何线程解决方案都要清晰得多。有一些现成的库可以帮到你。 (我不知道目前的状况,但几年前我使用了原来的asyncio-tkinter
。)
唯一的问题是您无法使用telnetlib
,因为它不是为asyncio
设计的。但几乎可以肯定的是,有更现代的Telnet库。 (通过快速搜索,我找到了telnetlib3
,看起来很有前途,但我不太了解推荐它。)
当然这个解决方案需要重写你的大部分网络代码 - 但你不是很多,而且它没有工作,所以这看起来不是太多了悲剧。与此同时,您的tkinter代码只需要进行一行更改。