如何制作一个具有 readline 功能的扭曲的 python 客户端

2024-02-06

我正在尝试使用 Python Twisted 为简单的 TCP 服务器编写客户端。当然,我对 Python 还很陌生,刚刚开始研究 Twisted,所以我可能会做错。

服务器很简单,您打算使用 nc 或 telnet。没有认证。您只需连接并获得一个简单的控制台。我想编写一个添加一些 readline 功能的客户端(历史记录和像 ctrl-a/ctrl-e 这样的 emacs 是我想要的)

下面是我编写的代码,其工作效果与从命令行使用 netcat 一样好,如下所示nc localhost 4118

from twisted.internet import reactor, protocol, stdio
from twisted.protocols import basic
from sys import stdout

host='localhost'
port=4118
console_delimiter='\n'

class MyConsoleClient(protocol.Protocol):
    def dataReceived(self, data):
        stdout.write(data)
        stdout.flush()

    def sendData(self,data):
        self.transport.write(data+console_delimiter)

class MyConsoleClientFactory(protocol.ClientFactory):
    def startedConnecting(self,connector):
        print 'Starting connection to console.'

    def buildProtocol(self, addr):
        print 'Connected to console!'
        self.client = MyConsoleClient()
        self.client.name = 'console'
        return self.client

    def clientConnectionFailed(self, connector, reason):
        print 'Connection failed with reason:', reason

class Console(basic.LineReceiver):
    factory = None
    delimiter = console_delimiter

    def __init__(self,factory):
        self.factory = factory

    def lineReceived(self,line):
        if line == 'quit':
            self.quit()
        else:
            self.factory.client.sendData(line)

    def quit(self):
        reactor.stop()

def main():
    factory = MyConsoleClientFactory()
    stdio.StandardIO(Console(factory))
    reactor.connectTCP(host,port,factory)
    reactor.run()

if __name__ == '__main__':
    main()

输出:

$ python ./console-console-client.py 
Starting connection to console.
Connected to console!
console> version
d305dfcd8fc23dc6674a1d18567a3b4e8383d70e
console> number-events
338
console> quit

我看过

Python Twisted 与 Cmd 模块集成 https://stackoverflow.com/questions/8568241/python-twisted-integration-with-cmd-module

这对我来说确实不成功。示例代码工作得很好,但是当我介绍网络时,我似乎与 stdio 存在竞争条件。这个较旧的链接似乎提倡类似的方法(在单独的线程中运行 readline),但我并没有走得太远。

我还研究了扭曲的海螺侮辱,但除了演示示例之外,我没有运气得到任何东西。

制作一个提供 readline 支持的基于终端的客户端的最佳方法是什么?

http://twistedmatrix.com/documents/current/api/twisted.conch.stdio.html http://twistedmatrix.com/documents/current/api/twisted.conch.stdio.html

看起来很有希望,但我很困惑如何使用它。

http://twistedmatrix.com/documents/current/api/twisted.conch.recvline.HistoricRecvLine.html http://twistedmatrix.com/documents/current/api/twisted.conch.recvline.HistoricRecvLine.html

例如,似乎还提供了对处理向上和向下箭头的支持,但我无法切换 Console 来继承 HistoricRecVLine 而不是 LineReceiver 来运行。

也许扭曲是使用错误的框架,或者我应该使用所有海螺类。我只是喜欢它的事件驱动风格。是否有更好/更简单的方法来在扭曲的客户端中提供 readline 或类似 readline 的支持?


我最终通过不使用 Twisted 框架来解决这个问题。这是一个很棒的框架,但我认为它对于这项工作来说是错误的工具。相反,我使用了telnetlib, cmd and readline模块。

我的服务器是异步的,但这并不意味着我的客户端需要如此,所以我使用telnetlib用于我与服务器的通信。这使得创建一个ConsoleClient类有哪些子类cmd.Cmd并获取历史记录和类似 emacs 的快捷方式。

#! /usr/bin/env python

import telnetlib
import readline
import os
import sys
import atexit
import cmd
import string

HOST='127.0.0.1'
PORT='4118'

CONSOLE_PROMPT='console> '

class ConsoleClient(cmd.Cmd):
    """Simple Console Client in Python.  This allows for readline functionality."""

    def connect_to_console(self):
        """Can throw an IOError if telnet connection fails."""
        self.console = telnetlib.Telnet(HOST,PORT)
        sys.stdout.write(self.read_from_console())
        sys.stdout.flush()

    def read_from_console(self):
        """Read from console until prompt is found (no more data to read)
        Will throw EOFError if the console is closed.
        """
        read_data = self.console.read_until(CONSOLE_PROMPT)
        return self.strip_console_prompt(read_data)

    def strip_console_prompt(self,data_received):
        """Strip out the console prompt if present"""
        if data_received.startswith(CONSOLE_PROMPT):
            return data_received.partition(CONSOLE_PROMPT)[2]
        else:
            #The banner case when you first connect
            if data_received.endswith(CONSOLE_PROMPT):
                return data_received.partition(CONSOLE_PROMPT)[0]
            else:
                return data_received

    def run_console_command(self,line):
        self.write_to_console(line + '\n')
        data_recved = self.read_from_console()        
        sys.stdout.write(self.strip_console_prompt(data_recved))        
        sys.stdout.flush()

    def write_to_console(self,line):
        """Write data to the console"""
        self.console.write(line)
        sys.stdout.flush()

    def do_EOF(self, line): 
        try:
            self.console.write("quit\n")
            self.console.close()
        except IOError:
            pass
        return True

    def do_help(self,line):
        """The server already has it's own help command.  Use that"""
        self.run_console_command("help\n")

    def do_quit(self, line):        
        return self.do_EOF(line)

    def default(self, line):
        """Allow a command to be sent to the console."""
        self.run_console_command(line)

    def emptyline(self):
        """Don't send anything to console on empty line."""
        pass


def main():
    histfile = os.path.join(os.environ['HOME'], '.consolehistory') 
    try:
        readline.read_history_file(histfile) 
    except IOError:
        pass
    atexit.register(readline.write_history_file, histfile) 

    try:
        console_client = ConsoleClient()
        console_client.prompt = CONSOLE_PROMPT
        console_client.connect_to_console()
        doQuit = False;
        while doQuit != True:
            try:
                console_client.cmdloop()
                doQuit = True;
            except KeyboardInterrupt:
                #Allow for ^C (Ctrl-c)
                sys.stdout.write('\n')
    except IOError as e:
        print "I/O error({0}): {1}".format(e.errno, e.strerror)
    except EOFError:
        pass

if __name__ == '__main__':
    main()

我所做的一项更改是删除从服务器返回的提示并使用Cmd.prompt显示给用户。我的原因是支持 Ctrl-c 更像一个 shell。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何制作一个具有 readline 功能的扭曲的 python 客户端 的相关文章

  • python future 和元组解包

    实现像使用 future 进行元组解包这样的事情的优雅 惯用的方法是什么 我有这样的代码 a b c f x y g a b z h y c 我想将其转换为使用期货 理想情况下我想写一些类似的东西 a b c ex submit f x y
  • python 中的代表

    我实现了这个简短的示例来尝试演示一个简单的委托模式 我的问题是 这看起来我已经理解了委托吗 class Handler def init self parent None self parent parent def Handle self
  • Python模块可以访问英语词典,包括单词的定义[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个 python 模块 它可以帮助我从英语词典中获取单词的定义 当然有enchant 这可以帮助我检查该单词是否存在于英语中
  • Django 模型在模板中不可迭代

    我试图迭代模型以获取列表中的第一个图像 但它给了我错误 即模型不可迭代 以下是我的模型和模板的代码 我只需要获取与单个产品相关的列表中的第一个图像 模型 py class Product models Model title models
  • Pandas 中允许重复列

    我将一个大的 CSV 包含股票财务数据 文件分割成更小的块 CSV 文件的格式不同 像 Excel 数据透视表之类的东西 第一列的前几行包含一些标题 公司名称 ID 等在以下列中重复 因为一家公司有多个属性 而不是一家公司只有一栏 在前几行
  • 填充两个函数之间的区域

    import matplotlib pyplot as plt import numpy as np def domain x np arange 0 10 0 001 f1 lambda x 2 x x 2 0 5 plt plot x
  • Pandas 数据帧到 numpy 数组 [重复]

    这个问题在这里已经有答案了 我对 Python 很陌生 经验也很少 我已经设法通过复制 粘贴和替换我拥有的数据来使一些代码正常工作 但是我一直在寻找如何从数据框中选择数据 但无法理解这些示例并替换我自己的数据 总体目标 如果有人真的可以帮助
  • 切片 Dataframe 时出现 KeyError

    我的代码如下所示 d pd read csv Collector Output csv df pd DataFrame data d dfa df copy dfa dfa rename columns OBJECTID Object ID
  • 从 python 发起 SSH 隧道时出现问题

    目标是在卫星服务器和集中式注册数据库之间建立 n 个 ssh 隧道 我已经在我的服务器之间设置了公钥身份验证 因此它们只需直接登录而无需密码提示 怎么办 我试过帕拉米科 它看起来不错 但仅仅建立一个基本的隧道就变得相当复杂 尽管代码示例将受
  • 将 matplotlib 颜色图集中在特定值上

    我正在使用 matplotlib 颜色图 seismic 绘制绘图 并且希望白色以 0 为中心 当我在不进行任何更改的情况下运行脚本时 白色从 0 下降到 10 我尝试设置 vmin 50 vmax 50 但在这种情况下我完全失去了白色 关
  • 将 2D NumPy 数组按元素相乘并求和

    我想知道是否有一种更快的方法 专用 NumPy 函数来执行 2D NumPy 数组的元素乘法 然后对所有元素求和 我目前使用np sum np multiply A B 其中 A B 是相同维度的 NumPy 数组m x n 您可以使用np
  • 在 Pandas 中使用正则表达式的多种模式

    我是Python编程的初学者 我正在探索正则表达式 我正在尝试从 描述 列中提取一个单词 数据库名称 我无法给出多个正则表达式模式 请参阅下面的描述和代码 描述 Summary AD1 Low free DATA space in data
  • python Soap zeep模块获取结果

    我从 SOAP API 得到如下结果 client zeep Client wsdl self wsdl transport transport auth header lb E authenticate self login res cl
  • 使用 Firefox 绕过弹出窗口下载文件:Selenium Python

    我正在使用 selenium 和 python 来从中下载某些文件web page http www oceanenergyireland com testfacility corkharbour observations 我之前一直使用设
  • mac osx 10.8 上的初学者 python

    我正在学习编程 并且一直在使用 Ruby 和 ROR 但我觉得我更喜欢 Python 语言来学习编程 虽然我看到了 Ruby 和 Rails 的优点 但我觉得我需要一种更容易学习编程概念的语言 因此是 Python 但是 我似乎找不到适用于
  • 使用yield 进行字典理解

    作为一个人为的例子 myset set a b c d mydict item yield join item s for item in myset and list mydict gives as cs bs ds a None b N
  • 如何为每个屏幕添加自己的 .py 和 .kv 文件?

    我想为每个屏幕都有一个单独的 py 和 kv 文件 应通过 main py main kv 中的 ScreenManager 选择屏幕 设计应从文件 screen X kv 加载 类等应从文件 screen X py 加载 Screens
  • 当鼠标悬停在上面时,intellisense vscode 不显示参数或文档

    我正在尝试将整个工作流程从 Eclipse 和 Jupyter Notebook 迁移到 VS Code 我安装了 python 扩展 它应该带有 Intellisense 但它只是部分更糟糕 我在输入句点后收到建议 但当将鼠标悬停在其上方
  • 您可以使用关键字参数而不提供默认值吗?

    我习惯于在 Python 中使用这样的函数 方法定义 def my function arg1 None arg2 default do stuff here 如果我不供应arg1 or arg2 那么默认值None or default
  • Scrapy Spider不存储状态(持久状态)

    您好 有一个基本的蜘蛛 可以运行以获取给定域上的所有链接 我想确保它保持其状态 以便它可以从离开的位置恢复 我已按照给定的网址进行操作http doc scrapy org en latest topics jobs html http d

随机推荐