【发布时间】: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