python 创建 Telnet 客户端

目录

前言

1. Telnet 客户端框架

2. Telnet 代码分解

2.1 基于 TK 创建会话窗口

2.1.1 创建 Text 文本控件

2.1.2 创建 Frame 容器

2.1.2.1 基于 Frame 容器创建主机地址输入框

2.1.2.1.1 主机地址输入框绑定焦点事件

2.1.2.2 创建 Telnet 连接按钮控件

2.1.2.3 创建 Telnet 断开按钮控件

2.1.2.4 基于 Frame 容器创建发送命令输入框

2.1.2.4.1 发送命令输入框绑定焦点事件

2.1.2.5 创建执行命令按钮控件

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

2.2.1 Telnet 连接服务器

2.2.2 Telnet 断开服务器 

2.3 Telnet 会话交互过程

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

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

3. Telnet 客户端代码总览 

4. Telnet 客户端效果展示 

5. 总结


前言

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

1. 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 客户端效果展示 

5. 总结

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

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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

积步千里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值