当前位置:网站首页 > 更多 > 编程开发 > 正文

[Python] python 创建 Telnet 客户端

作者:CC下载站 日期:2023-10-11 19:28:55 浏览:29 分类:编程开发


前言

最近由于某些特殊项目的需要,匆忙通过 python 实现了一个简易版的 Telnet 客户端。这个客户端目前来说是有缺陷的(比如,不能 vi 读写文件内容,不能执行阻塞型命令 ping 等),但是感觉比较好玩,所以想与大家分享一下。

1. Telnet 客户端框架

[Python] python 创建 Telnet 客户端

2. Telnet 代码分解

接下来,我们就基于 Telnet客户端框架 来逐步拆分讲解代码构成。

2.1 基于 TK 创建会话窗口

# 创建窗口并设置标题
window = tk.Tk()
window.title("Telnet客户端")

# 设置tk.Tk窗口的背景颜色为浅蓝色
window.config(bg="sky blue")

2.1.1 创建 Text 文本控件

# 创建一个Text文本控件
console_text = tk.Text(window, width=200, height=70, bg="black", fg="white")
console_text.pack(pady=5)

# 定义一个字体样式
console_text.tag_configure("bold_tag", font=("Arial", 11))

2.1.2 创建 Frame 容器

# 创建一个Frame用于放置输入框和按钮,并设置Frame在下方空开5个空格
frame = tk.Frame(window, bg="sky blue")
frame.pack(pady=5)
2.1.2.1 基于 Frame 容器创建主机地址输入框
# 创建一个输入框控件,并放置在Frame中,同时设置右侧空开3个空格
host_addr_entry = tk.Entry(frame, width=50, font=("Arial", 12, "bold"))
host_addr_entry.insert(0, "请输入主机地址...")
host_addr_entry.config(fg="gray")
host_addr_entry.pack(side=tk.LEFT, padx=3)
2.1.2.1.1 主机地址输入框绑定焦点事件
# 绑定获取焦点和失去焦点事件,显示和隐藏提示语
host_addr_entry.bind("<FocusIn>", on_host_entry_focus_in)
host_addr_entry.bind("<FocusOut>", on_host_entry_focus_out)

# 获取焦点事件
def on_host_entry_focus_in(event):
    if host_addr_entry.get() == "请输入主机地址...":
        host_addr_entry.delete(0, tk.END)
        host_addr_entry.config(fg="black")

# 失去焦点事件
def on_host_entry_focus_out(event):
    if host_addr_entry.get() == "":
        host_addr_entry.insert(0, "请输入主机地址...")
        host_addr_entry.config(fg="gray")
2.1.2.2 创建 Telnet 连接按钮控件
# 创建一个按钮控件,并放置在Frame中
connect_button = tk.Button(frame, text="连接 Telnet", font=("Arial", 12, "bold"), fg="white", bg="#46C0FB", command=connect_telnet)
connect_button.pack(side=tk.LEFT, padx=3)
2.1.2.3 创建 Telnet 断开按钮控件
# 创建断开按钮控件,并放置在Frame中,右侧空开3个空格
disconnect_button = tk.Button(frame, text="断开 Telnet", font=("Arial", 12, "bold"), fg="white", bg="#46C0FB", command=disconnect_telnet, state=tk.DISABLED)
disconnect_button.pack(side=tk.LEFT, padx=3)
2.1.2.4 基于 Frame 容器创建发送命令输入框
# 创建一个输入框控件,并放置在Frame中,同时设置右侧空开3个空格
command_entry = tk.Entry(frame, width=50, font=("Arial", 12, "bold"))
command_entry.insert(0, "请发送指令...")
command_entry.config(fg="gray")
command_entry.pack(side=tk.LEFT, padx=12)
2.1.2.4.1 发送命令输入框绑定焦点事件
# 绑定获取焦点和失去焦点事件,显示和隐藏提示语
command_entry.bind("<FocusIn>", on_entry_focus_in)
command_entry.bind("<FocusOut>", on_entry_focus_out)

# 获取焦点事件
def on_entry_focus_in(event):
    if command_entry.get() == "请发送指令...":
        command_entry.delete(0, tk.END)
        command_entry.config(fg="black")

# 失去焦点事件
def on_entry_focus_out(event):
    if command_entry.get() == "":
        command_entry.insert(0, "请发送指令...")
        command_entry.config(fg="gray")
2.1.2.5 创建执行命令按钮控件
# 创建执行按钮控件,并放置在Frame中,右侧空开3个空格
execute_button = tk.Button(frame, text="执行命令", font=("Arial", 12, "bold"), fg="white", bg="#46C0FB", command=execute_command, state=tk.DISABLED)
execute_button.pack(side=tk.LEFT)

2.2 Telnet 连接与断开服务器过程

2.2.1 Telnet 连接服务器

def connect_telnet():
    host = host_addr_entry.get() # 获取输入框内的主机地址
    port = 23            # 默认telnet端口
    username = ';root';    # 登录用户名
    password = ';123456';  # 登录密码

    try:
        # 连接Telnet服务器
        telnet_client = telnetlib.Telnet(host, port, timeout=5)
        console_text.insert(tk.END, "成功连接到Telnet服务器。\n", "bold_tag")
        connect_button.config(state=tk.DISABLED)
        disconnect_button.config(state=tk.NORMAL)
        execute_button.config(state=tk.NORMAL)

        # 输入登录用户名
        telnet_client.read_until(b';login:';)
        telnet_client.write(username.encode(';ascii';) + b"\n")

        # 输入登录密码
        telnet_client.read_until(b';Password:';)
        telnet_client.write(password.encode(';ascii';) + b"\n")
        print(';成功登录到设备:'; + host)

        # 启动后台信息接收线程
        receive_thread = threading.Thread(target=receive_background_info)
        receive_thread.start()

    except Exception as e:
        console_text.insert(tk.END, f"连接失败: {e}\n", "bold_tag")

2.2.2 Telnet 断开服务器 

def disconnect_telnet():
    if telnet_client:
        telnet_client.close()
        console_text.insert(tk.END, "已断开Telnet连接。\n", "bold_tag")
        connect_button.config(state=tk.NORMAL)
        disconnect_button.config(state=tk.DISABLED)
        execute_button.config(state=tk.DISABLED)

2.3 Telnet 会话交互过程

2.3.1 Telnet 客户端向服务器发送命令

def execute_command():
    command = command_entry.get() + "\n"
    telnet_client.write(command.encode(';ascii';))
    command_entry.delete(0, tk.END)

2.3.2 Telnet 客户端接收服务器返回的数据 

def receive_background_info():
    while True:
        try:
            output_data = telnet_client.read_very_eager().decode(';utf-8';)
            if output_data:
                clean_color_data = remove_color_codes(output_data.strip())
                console_text.insert(tk.END, clean_color_data, "bold_tag")
                time.sleep(0.5)
            except EOFError:
                break
            except Exception as e:
                console_text.insert(tk.END, f"错误: {e}\n", "bold_tag")
                break

    def remove_color_codes(data):
        # 使用正则表达式匹配ANSI转义码,并替换为空字符串
        ansi_escape = re.compile(r';\x1B\[[0-?]*[ -/]*[@-~]';)
        return ansi_escape.sub(';';, data)

3. Telnet 客户端代码总览 

import tkinter as tk
import telnetlib
import threading
import time
import re

class TeneltTool:
    def __init__(self):
        self.window = tk.Tk()
        self.window.title("Telnet客户端")
        # 设置tk.Tk窗口的背景颜色为浅蓝色
        self.window.config(bg="sky blue")

        # 创建一个200x70的Text文本控件,并且设置背景为黑色
        self.console_text = tk.Text(self.window, width=200, height=70, bg="black", fg="white")
        self.console_text.pack(pady=5)
        # 定义一个字体样式
        self.console_text.tag_configure("bold_tag", font=("Arial", 11))

        # 创建一个Frame用于放置输入框和按钮,并设置Frame在下方空开5个空格
        frame = tk.Frame(self.window, bg="sky blue")
        frame.pack(pady=5)

        # 创建一个输入框控件,并放置在Frame中,同时设置右侧空开3个空格
        self.host_addr_entry = tk.Entry(frame, width=50, font=("Arial", 12, "bold"))
        self.host_addr_entry.insert(0, "请输入主机地址...")
        self.host_addr_entry.config(fg="gray")
        self.host_addr_entry.pack(side=tk.LEFT, padx=3)

        # 创建一个按钮控件,并放置在Frame中
        self.connect_button = tk.Button(frame, text="连接 Telnet", font=("Arial", 12, "bold"), fg="white", bg="#46C0FB",
                                        command=self.connect_telnet)
        self.connect_button.pack(side=tk.LEFT, padx=3)

        # 创建断开按钮控件,并放置在Frame中,右侧空开3个空格
        self.disconnect_button = tk.Button(frame, text="断开 Telnet", font=("Arial", 12, "bold"), fg="white",
                                           bg="#46C0FB", command=self.disconnect_telnet, state=tk.DISABLED)
        self.disconnect_button.pack(side=tk.LEFT, padx=3)

        # 绑定获取焦点和失去焦点事件,显示和隐藏提示语
        self.host_addr_entry.bind("<FocusIn>", self.on_host_entry_focus_in)
        self.host_addr_entry.bind("<FocusOut>", self.on_host_entry_focus_out)

        # 创建一个输入框控件,并放置在Frame中,同时设置右侧空开3个空格
        self.command_entry = tk.Entry(frame, width=50, font=("Arial", 12, "bold"))
        self.command_entry.insert(0, "请发送指令...")
        self.command_entry.config(fg="gray")
        self.command_entry.pack(side=tk.LEFT, padx=12)

        # 绑定获取焦点和失去焦点事件,显示和隐藏提示语
        self.command_entry.bind("<FocusIn>", self.on_entry_focus_in)
        self.command_entry.bind("<FocusOut>", self.on_entry_focus_out)

        # 创建执行按钮控件,并放置在Frame中,右侧空开3个空格
        self.execute_button = tk.Button(frame, text="执行命令", font=("Arial", 12, "bold"), fg="white",
                                        bg="#46C0FB", command=self.execute_command, state=tk.DISABLED)
        self.execute_button.pack(side=tk.LEFT)

        self.telnet_client = None
        self.receive_thread = None

    def on_host_entry_focus_in(self, event):
        if self.host_addr_entry.get() == "请输入主机地址...":
            self.host_addr_entry.delete(0, tk.END)
            self.host_addr_entry.config(fg="black")

    def on_host_entry_focus_out(self, event):
        if self.host_addr_entry.get() == "":
            self.host_addr_entry.insert(0, "请输入主机地址...")
            self.host_addr_entry.config(fg="gray")

    def on_entry_focus_in(self, event):
        if self.command_entry.get() == "请发送指令...":
            self.command_entry.delete(0, tk.END)
            self.command_entry.config(fg="black")

    def on_entry_focus_out(self, event):
        if self.command_entry.get() == "":
            self.command_entry.insert(0, "请发送指令...")
            self.command_entry.config(fg="gray")

    def connect_telnet(self):
        host = self.host_addr_entry.get() # 获取输入框内的主机地址
        port = 23             # 默认telnet端口
        username = ';root';     # 登录用户名
        password = ';123456';   # 登录密码

        try:
            # 连接Telnet服务器
            self.telnet_client = telnetlib.Telnet(host, port, timeout=5)
            self.console_text.insert(tk.END, "成功连接到Telnet服务器。\n", "bold_tag")
            self.connect_button.config(state=tk.DISABLED)
            self.disconnect_button.config(state=tk.NORMAL)
            self.execute_button.config(state=tk.NORMAL)
            # 输入登录用户名
            self.telnet_client.read_until(b';login:';)
            self.telnet_client.write(username.encode(';ascii';) + b"\n")
            # 输入登录密码
            self.telnet_client.read_until(b';Password:';)
            self.telnet_client.write(password.encode(';ascii';) + b"\n")
            print(';成功登录到设备:'; + host)

            # 启动后台信息接收线程
            self.receive_thread = threading.Thread(target=self.receive_background_info)
            self.receive_thread.start()

        except Exception as e:
            self.console_text.insert(tk.END, f"连接失败: {e}\n", "bold_tag")

    def disconnect_telnet(self):
        if self.telnet_client:
            self.telnet_client.close()
            self.console_text.insert(tk.END, "已断开Telnet连接。\n", "bold_tag")
            self.connect_button.config(state=tk.NORMAL)
            self.disconnect_button.config(state=tk.DISABLED)
            self.execute_button.config(state=tk.DISABLED)

    def execute_command(self):
        command = self.command_entry.get() + "\n"
        self.telnet_client.write(command.encode(';ascii';))
        self.command_entry.delete(0, tk.END)

    def receive_background_info(self):
        while True:
            try:
                output_data = self.telnet_client.read_very_eager().decode(';utf-8';)
                if output_data:
                    clean_color_data = self.remove_color_codes(output_data.strip())
                    self.console_text.insert(tk.END, clean_color_data, "bold_tag")
                    # self.console_text.see(tk.END)
                time.sleep(0.5)
            except EOFError:
                break
            except Exception as e:
                self.console_text.insert(tk.END, f"错误: {e}\n", "bold_tag")
                break

    def remove_color_codes(self, data):
        # 使用正则表达式匹配ANSI转义码,并替换为空字符串
        ansi_escape = re.compile(r';\x1B\[[0-?]*[ -/]*[@-~]';)
        return ansi_escape.sub(';';, data)

if __name__ == "__main__":
    tenelt_tool = TeneltTool()
    tenelt_tool.window.mainloop()

4. Telnet 客户端效果展示 

[Python] python 创建 Telnet 客户端

[Python] python 创建 Telnet 客户端

5. 总结

由于这个工具是匆忙之间创作的,所以还存在一些缺陷,大家如果感兴趣,就拷贝源码自行优化吧。 

好啦,本章内容到此结束,感谢大家的热爱与支持~

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯