你说过:
假设一时兴起,我想……向所有客户发送友好的信息
和
我想当我坐在服务器上时,我想要做的是在 Python 中以交互方式生成事件。
我将把它翻译成“我想在我的反应堆运行时有一个键盘界面”,并给你一个例子。
在 Twisted 中,键盘只是另一个 IO 接口,您可以与所有其他 IO 一起使用,我将提供的示例适用于 unix/posix 类型的平台,尽管同样的想法当然也可以在其他操作系统上实现。
(免责声明:这个例子有点乱,因为它在 tty 上设置了 cbreak 模式,这是我喜欢为交互式控制做的事情,但它肯定不是必需的。)
#!/usr/bin/python
import sys # so I can get at stdin
import os # for isatty
import termios, tty # access to posix IO settings
from twisted.internet import reactor
from twisted.internet import stdio # the stdio equiv of listenXXX
from twisted.protocols import basic # for lineReceiver for keyboard
from twisted.internet.protocol import Protocol, ServerFactory
class Cbreaktty(object):
org_termio = None
my_termio = None
def __init__(self, ttyfd):
if(os.isatty(ttyfd)):
self.org_termio = (ttyfd, termios.tcgetattr(ttyfd))
tty.setcbreak(ttyfd)
print ' Set cbreak mode'
self.my_termio = (ttyfd, termios.tcgetattr(ttyfd))
else:
raise IOError #Not something I can set cbreak on!
def retToOrgState(self):
(tty, org) = self.org_termio
print ' Restoring terminal settings'
termios.tcsetattr(tty, termios.TCSANOW, org)
class MyClientConnections(Protocol):
def connectionMade(self):
print "Got new client!"
self.factory.clients.append(self)
def connectionLost(self, reason):
print "Lost a client!"
self.factory.clients.remove(self)
class MyServerFactory(ServerFactory):
protocol = MyClientConnections
def __init__(self):
self.clients = []
def sendToAll(self, message):
for c in self.clients:
c.transport.write(message)
def hello_to_all(self):
self.sendToAll("A friendly message, sent on a whim\n")
print "sending friendly..."
class KeyEater(basic.LineReceiver):
def __init__(self, hello_callback):
self.setRawMode() # Switch from line mode to "however much I got" mode
self.hello_to_all = hello_callback
def rawDataReceived(self, data):
key = str(data).lower()[0]
if key == 's':
self.hello_to_all()
elif key == 'q':
reactor.stop()
else:
print "Press 's' to send a message to all clients, 'q' to shutdown"
def main():
client_connection_factory = MyServerFactory()
try:
termstate = Cbreaktty(sys.stdin.fileno())
except IOError:
sys.stderr.write("Error: " + sys.argv[0] + " only for use on interactive ttys\n")
sys.exit(1)
keyboardobj = KeyEater(client_connection_factory.hello_to_all)
stdio.StandardIO(keyboardobj,sys.stdin.fileno())
reactor.listenTCP(5000, client_connection_factory)
reactor.run()
termstate.retToOrgState()
if __name__ == '__main__':
main()
如果您运行上述代码(.. 假设您在 unix/posix 上),您将拥有一个反应器,它既等待/服务 TCP 连接,又等待密钥在标准输入上发生。键入键 's' 将向所有连接的客户端发送消息。
这是我经常用于对扭曲应用程序进行异步控制的方法,尽管它肯定只是其他答案中提到的众多方法之一。