【问题标题】:Python Threading and Telnet unexpected resultsPython 线程和 Telnet 意外结果
【发布时间】:2021-04-02 03:32:41
【问题描述】:

我编写了一个脚本,它可以远程登录到某些网络设备并提取库存并将其放入文件中。我使用线程来加速脚本,因为我有大约 160 个节点。我编写了一个远程登录到每个节点的函数,检索库存,将输出写入文件,然后断开会话。当我在一个函数下完成这三个步骤时,该脚本运行良好。但是,我决定创建一个类并将这三个步骤分解为不同的方法。现在,当我运行脚本时,它只从列表中的第一个节点检索数据。我需要一些帮助来找出脚本无法正常工作的原因。

import concurrent.futures
import time
import telnetlib
from myFunctions import get_node_list_TA5K

class Ta5kTelnet:

    def __init__(self):
        self.tn = telnetlib.Telnet()

    def connect(self, hostname, username, password):
        self.tn.open(hostname, 23, 5)
        self.tn.read_until(b'Username:', 5)
        self.tn.write(username.encode('ascii') + b'\n')
        self.tn.read_until(b'Password:', 5)
        self.tn.write(password.encode('ascii') + b'\n')
        if b'>' in self.tn.read_until(b'>', 5):
            self.tn.write(b'en\n')
            self.tn.read_until(b'#', 5)
            self.tn.write(b'term len 0\n')
            output = self.tn.read_until(b'#', 5)
            return output
        else:
            print(f'{hostname} is spare shelf')

    def send(self, command, waitfor):
        self.tn.write(command + b'\n')
        result = self.tn.read_until(waitfor, 180).decode()
        return result
    
    def disconnect(self):
        self.tn.close()


tlnt = Ta5kTelnet()


def inventory(node_names):
    tlnt.connect(node_names, 'username', 'password')
    shelf_inventory = tlnt.send(b'show system inventory', b'#')
    tlnt.disconnect()
    with open(f'{node_names}_inventory.txt', 'a') as f:
        f.write(shelf_inventory)



#adtran_nodes = get_node_list_TA5K()
adtran_nodes = ['BXR1-NODE1-COT1', 'BXR6-NODE1-COT6']


start = time.perf_counter()

with concurrent.futures.ThreadPoolExecutor() as executor:
    results = executor.map(inventory, adtran_nodes)



print(time.perf_counter() - start)

【问题讨论】:

    标签: python multithreading telnetlib


    【解决方案1】:

    您正在跨两个线程共享一个 telnet 连接,并且没有锁定或同步。

    没有办法知道连接、登录、发送、read_until 序列的运行顺序。

    每个线程都需要自己的连接对象。

    此外,我将重构一些东西以从telnetlib.Telnet 派生,并在此期间确保连接始终正确关闭,使其成为具有__enter____exit__ 的上下文管理器:

    import concurrent.futures
    import telnetlib
    
    USERNAME = "username"
    PASSWORD = "password"
    
    
    class Ta5kTelnet(telnetlib.Telnet):
        def __enter__(self):
            return self
    
        def __exit__(self, *args):
            self.close()
    
        def login(self, hostname, username, password):
            self.open(hostname, 23, 5)
            self.read_until(b"Username:", 5)
            self.write(username.encode("ascii") + b"\n")
            self.read_until(b"Password:", 5)
            self.write(password.encode("ascii") + b"\n")
            if b">" in self.read_until(b">", 5):
                self.write(b"en\n")
                self.read_until(b"#", 5)
                self.write(b"term len 0\n")
                return self.read_until(b"#", 5)
            raise RuntimeError(f"{hostname} is spare shelf")
    
        def send_command(self, command, waitfor):
            self.write(command + b"\n")
            return self.read_until(waitfor, 180).decode()
    
    
    def get_node_inventory(node_name):
        with Ta5kTelnet() as tlnt:
            tlnt.login(node_name, USERNAME, PASSWORD)
            shelf_inventory = tlnt.send_command(b"show system inventory", b"#")
        with open(f"{node_name}_inventory.txt", "a") as f:
            f.write(shelf_inventory)
    
    
    adtran_nodes = ["BXR1-NODE1-COT1", "BXR6-NODE1-COT6"]
    
    with concurrent.futures.ThreadPoolExecutor() as executor:
        results = executor.map(get_node_inventory, adtran_nodes)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-26
      • 2020-03-15
      • 1970-01-01
      • 1970-01-01
      • 2018-12-28
      • 1970-01-01
      相关资源
      最近更新 更多