我有一个标准的服务器 - 客户端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())
(注意:截断的代码段。可以找到完整代码here 链接代码已更新,因此不再相关。)
问题是,当用户正在键入并从服务器获取传入消息时,客户端会输出消息并再次提示输入。正在输入的消息仍在stdin缓冲区中,但已从屏幕上消失。如果用户按Enter键发送消息,整个消息将被发送,包括缓冲区中的内容,但在用户的屏幕上,只显示消息的第二部分,即中断后的部分。
我有一个可能的解决方案,就是当我提示输入时,我检查缓冲区中是否有任何内容并输出该提示符,但我不知道如何实现它。任何帮助表示赞赏。
答案 0 :(得分:1)
要实现您的解决方案,您必须以无缓冲的方式从stdin读取。 readline()和read()阻塞直到EOL或EOF。在按下返回键之前,您需要来自stdin的数据。要做到这一点,这可能会有所帮助:http://code.activestate.com/recipes/134892-getch-like-unbuffered-character-reading-from-stdin/当您要编写数据时,您可以从stdin读取,将其存储在某处并在输出消息后再次输出。由于不会为stdin调用select,因此请创建一个读取stdin的单独读取线程。到目前为止,使用锁来访问stdin的数据。
答案 1 :(得分:0)
作为问题评论中讨论的实现您自己的编辑行输入功能的替代方法,请考虑以下方法:更改滚动区域以省略屏幕的底线(用户输入行)并仅暂时进入滚动区域输出传入服务器消息。 That answer包含一个示例。
答案 2 :(得分:0)
问题似乎是你让来自其他用户的消息中断输入。我建议你要么一次只听一件事(当用户打字时你让他完成并在听远程消息之前按回车键)或你听用户的输入一个一次键入并建立自己的缓冲区(参见Polling the keyboard (detect a keypress) in python)。后一种方法的缺点是你需要实现密钥编辑等。可能有一个库可以为你完成这个。
请注意,在大多数聊天程序中,您键入的区域位于单独的窗口/屏幕区域,而不是您看到消息的位置。在此消息区域中完成所有消息(您的以及其他消息)。也许您只能在屏幕上的其他位置使用显示消息(独立于输入)。