没什么复杂的,也不需要任何包装。在
它唯一的问题是它需要在程序退出时将终端恢复到正常状态。在
也就是说,如果程序崩溃,终端将无法恢复,用户将看不到他在输入什么。在
但如果用户知道自己在做什么,他可以强制重启shell,一切都会恢复正常。在
对于corse,您可以更轻松地使用此代码并使用raw_input()来完成这些工作。在from thread import start_new_thread as thread
from time import sleep
# Get only one character from stdin without echoing it to stdout
import termios
import fcntl
import sys
import os
fd = sys.stdin.fileno()
oldterm, oldflags = None, None
def prepareterm ():
"""Turn off echoing"""
global oldterm, oldflags
if oldterm!=None and oldflags!=None: return
oldterm = termios.tcgetattr(fd)
newattr = oldterm[:] # Copy of attributes to change
newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
termios.tcsetattr(fd, termios.TCSANOW, newattr)
oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)
def restoreterm ():
"""Restore terminal to its previous state"""
global oldterm, oldflags
if oldterm==None and oldflags==None: return
termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
oldterm, oldflags = None, None
def getchar():
"""Get character from stdin"""
prepareterm()
while 1:
try:
c = sys.stdin.read(1)
break
except IOError:
try: sleep(0.001)
except: restoreterm(); raise KeyboardInterrupt
restoreterm()
return c
def control ():
"""Waits for keypress"""
global running, done
while running:
c = getchar().lower()
print "Keypress:", c
if c=="q": print "Quitting!"; running = 0; break
done += 1
def work ():
"""Does the server-client part"""
global done
while running:
# Do your stuff here!!!
# Just to illustrate:
print "I am protending to work!\nPress Q to kill me!"
sleep(1)
print "I am done!\nExiting . . ."
done += 1
# Just to feel better
import atexit
atexit.register(restoreterm)
# Start the program
running = 1
done = 0
thread(work, ())
thread(control, ())
# Block the program not to close when threads detach from the main one:
while running:
try: sleep(0.2)
except: running = 0
# Wait for both threads to finish:
while done!=2:
try: sleep(0.001)
except: pass # Ignore KeyboardInterrupt
restoreterm() # Just in case!
在实践中,程序应该永远不能退出没有恢复到正常的终端,但狗屎发生了。在
现在,您可以通过只使用一个线程和放在主线程中的工作循环来简化事情,并使用原始输入从用户处获取命令。
或者更好的方法是,将服务器客户端代码放在后台,等待主线程中的输入。在
使用线程模块而不是原始线程也可能更安全。在
如果您使用asyncore模块,您将让每个客户机自己运行,并且您的主线程将被异步循环().
您可以重写它,即重写它以检查输入和其他您希望执行的操作,同时保持异步检查同步。
另外,重负载需要重写它内部的一些讨厌的函数,因为它的缓冲区被固定为512字节,如果我没弄错的话。否则,这可能是一个很好的解决你的问题。在
最后,为了清楚起见,无回音用户输入的代码是从getpass模块中获取并改编的。
只有一点点是我的。在