Python 线程和 Telnet 意外结果
Python Threading and Telnet unexpected results
我编写了一个脚本,可以远程登录到某些网络设备并提取清单并将其放入文件中。我使用线程来加速脚本,因为我有大约 160 个节点。我写了一个函数,远程登录到每个节点,检索清单,将输出写入文件,然后断开会话。当我在一个函数下执行这三个步骤时,该脚本效果很好。但是,我决定创建一个 class 并将这三个步骤分解为不同的方法。现在当我 运行 脚本时,它只从列表中的第一个节点检索数据。我需要一些帮助来弄清楚为什么脚本不起作用。
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)
您正在跨两个线程共享单个 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)
我编写了一个脚本,可以远程登录到某些网络设备并提取清单并将其放入文件中。我使用线程来加速脚本,因为我有大约 160 个节点。我写了一个函数,远程登录到每个节点,检索清单,将输出写入文件,然后断开会话。当我在一个函数下执行这三个步骤时,该脚本效果很好。但是,我决定创建一个 class 并将这三个步骤分解为不同的方法。现在当我 运行 脚本时,它只从列表中的第一个节点检索数据。我需要一些帮助来弄清楚为什么脚本不起作用。
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)
您正在跨两个线程共享单个 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)