如何使用Python TCP Socket运行交互式命令?以vim ./foo.txt为例
解决TCP Socket下运行交互式vim的问题
我懂你现在的痛点——直接通过socket传vim ./foo.txt命令,结果vim只在服务器端的终端里运行,客户端根本没法操作交互界面对吧?这事儿的核心原因是vim这类交互式程序依赖**伪终端(PTY)**来处理光标移动、按键输入、终端渲染这些细节,普通的socket字节流根本模拟不了终端环境。下面给你纯用Python socket模块搞定的方案,完全不用paramiko那些SSH库:
核心思路
- 服务器端:创建伪终端,让vim在这个pty环境里运行,把pty的输入输出和socket绑定,实现双向数据转发。
- 客户端:切换本地终端到原始模式(取消行缓冲,让每个按键直接发送给服务器),同时把socket收到的服务器端pty输出实时打印到本地终端。
服务器端代码
import socket import os import pty import subprocess def handle_client(conn): # 创建伪终端的主从端 master_fd, slave_fd = pty.openpty() # 启动vim,将其标准输入/输出/错误都绑定到伪终端的从端 proc = subprocess.Popen( ["vim", "./foo.txt"], stdin=slave_fd, stdout=slave_fd, stderr=slave_fd, start_new_session=True ) # 关闭从端文件描述符,因为subprocess已经接管了它 os.close(slave_fd) try: # 双向转发数据:socket ↔ 伪终端主端 while True: # 读取客户端发送的数据,写入伪终端 data = conn.recv(1024) if not data: break os.write(master_fd, data) # 读取伪终端的输出,发送给客户端 output = os.read(master_fd, 1024) if not output: break conn.sendall(output) finally: # 清理资源 proc.terminate() conn.close() os.close(master_fd) def main(): host = '0.0.0.0' port = 12345 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((host, port)) s.listen() print(f"服务器已启动,监听 {host}:{port}") while True: conn, addr = s.accept() print(f"客户端 {addr} 已连接") handle_client(conn) if __name__ == "__main__": main()
客户端代码
import socket import sys import termios import tty def save_terminal_settings(): # 保存当前终端的配置,用于后续恢复 return termios.tcgetattr(sys.stdin) def set_terminal_raw_mode(): # 将终端切换为原始模式:取消行缓冲,按键直接发送 tty.setraw(sys.stdin.fileno()) def restore_terminal(settings): # 恢复终端的原始配置 termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings) def main(): host = 'localhost' port = 12345 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((host, port)) old_terminal_settings = save_terminal_settings() try: set_terminal_raw_mode() # 双向转发数据:本地终端 ↔ socket while True: # 读取本地键盘输入,发送给服务器 input_char = sys.stdin.read(1) if not input_char: break s.sendall(input_char.encode()) # 读取服务器返回的数据,打印到本地终端 output_data = s.recv(1024) if not output_data: break sys.stdout.write(output_data.decode()) sys.stdout.flush() except KeyboardInterrupt: print("\n正在退出...") finally: # 无论如何都要恢复终端配置,避免终端异常 restore_terminal(old_terminal_settings) s.close() if __name__ == "__main__": main()
注意事项
- 先运行服务器脚本,再启动客户端脚本,就能在客户端终端里正常操作vim了,编辑的是服务器端的
foo.txt文件。 - 退出vim时用
:q命令,或者按Ctrl+C触发客户端的中断信号,终端会自动恢复正常配置。 - 这个方案仅支持类Unix系统(Linux/macOS),因为pty模块是Unix特有的;Windows系统没有伪终端机制,没法用这种方式实现。
内容的提问来源于stack exchange,提问作者user9249376
相关产品推荐
相关产品推荐

