【问题标题】:Prompting with previous input from sys.stdin提示来自 sys.stdin 的先前输入
【发布时间】:2016-12-09 07:33:03
【问题描述】:

我有一个标准的服务器-客户端 TCP 设置。基本思想是一个聊天系统。仅查看对话的客户端,客户端提示用户输入:

sys.stdout.write('<%s> ' % username)
sys.stdout.flush()

使用以下逻辑:

while True:
    socket_list = [sys.stdin, s]
    read_sockets, write_sockets, error_sockets = select.select(socket_list, [], [])
    for sock in read_sockets:
        if sock == s:
            data = sock.recv(4096)
            if data:
                output('\a\r%s' % data) #output incoming message
                sys.stdout.write('<%s> ' % username) #prompt for input
                sys.stdout.flush()
            else:
                raise SystemExit
        else:
            msg = getASCII(sys.stdin.readline()) # returns only the ascii
            if msg:
                s.send(msg)
            sys.stdout.write('<%s> ' % username)
            sys.stdout.flush())

(注意:截断的sn-p。完整代码可以找到here链接代码已经更新,因此不再相关。)

问题是,当用户正在输入时,它从服务器收到一条传入消息,客户端输出该消息并再次提示输入。正在输入的消息仍在标准输入缓冲区中,但已从屏幕上消失。如果用户按下回车键发送消息,整个消息将被发送,包括缓冲区中的内容,但在用户的屏幕上,只会显示消息的第二部分,即中断后的部分。

我有一个可能的解决方案,即当我提示输入时,我检查缓冲区中是否有任何内容并将其与提示一起输出,但我不知道如何实现它。任何帮助表示赞赏。

【问题讨论】:

  • 你用的是什么版本的 Python?
  • Python 2。不过支持 3 应该不难。
  • 要实现您的解决方案,您必须以无缓冲的方式从标准输入读取。 readline()read() 阻塞,直到 EOL 或 EOF。在按下返回键之前,您需要来自标准输入的数据。为了实现这一点,这可能会有所帮助:code.activestate.com/recipes/… 当您要写入数据时,您可以从标准输入读取数据,将其存储在某处并在输出消息后再次输出。由于不会为 stdin 调用 select,因此请创建一个单独的读取线程来读取 stdin。到目前为止,使用锁来访问标准输入的数据。
  • 哦,我应该提到,我在 Linux 上,所以选择工作。
  • @Munchhausen 说了什么。您可以使用 select() 执行此操作,但它会很混乱。考虑这个问题的更简单的方法是将客户端从服务器读取的内容和客户端写入服务器的内容完全分离到单独的线程中。一个线程只是读取键盘并将它得到的内容发送到服务器。另一个线程只是从服务器读取消息并将它们放在客户端的输出窗口中。两个线程永远不必查看彼此的数据,因此并发管理没有问题。

标签: python sockets io buffer stdin


【解决方案1】:

作为问题的 cmets 中讨论的实现自己的编辑行输入功能的替代方法,请考虑以下方法:更改滚动区域以省略屏幕的底线(用户输入行)并仅暂时进入滚动区域以输出传入的服务器消息。 That answer 包含一个示例。

【讨论】:

    【解决方案2】:

    问题似乎是您让来自其他用户的消息打断了打字。我建议您一次只听一件事(当用户键入时,您让他完成并在收听远程消息之前按回车键)您一次只听一个键并建立自己的缓冲区(参见Polling the keyboard (detect a keypress) in python)。后一种方法的缺点是您需要实现键编辑等。可能有一个库可以为您完成。

    请注意,在大多数聊天程序中,您键入的区域与您查看消息的位置不同,位于一个单独的窗口/屏幕区域中。完成后,所有消息(您的以及其他人的)都会显示在此消息区域中。也许您可以在屏幕上的其他地方只使用显示消息(独立于输入)。

    【讨论】:

      【解决方案3】:

      要实施您的解决方案,您必须以无缓冲的方式从标准输入读取。 readline() 和 read() 阻塞,直到 EOL 或 EOF。在按下返回键之前,您需要来自标准输入的数据。为了实现这一点,这可能会有所帮助:http://code.activestate.com/recipes/134892-getch-like-unbuffered-character-reading-from-stdin/ 当您要写入数据时,您可以从标准输入读取数据,将其存储在某处并在输出消息后再次输出。由于不会为 stdin 调用 select,因此请创建一个单独的读取线程来读取 stdin。到目前为止使用锁来访问标准输入的数据。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-12-05
        • 2018-09-15
        • 1970-01-01
        • 1970-01-01
        • 2019-06-16
        • 2021-09-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多