我刚刚被介绍通过this nice tutorial加入聊天应用程序,但我不确定如何根据我的需求进行调整。
假设,一时兴起,我希望聊天服务器向所有客户发送友好信息,例如"快乐的长周末!"。即我想让反应堆运行一些东西,但是它已经运行了(所以我不能提前安排,或者我不想要)。
我想做这样的事情:
def do_something():
# do something
# setup and run reactor
factory = Factory()
factory.clients = []
factory.protocol = MyServer
reactor.listenTCP(80, factory)
reactor.run() # asynchronously?
# clients connect...
reactor.callLater(0, do_something)
我尝试使用python线程,但它没有用。我看了these twisted examples,但他们最后都有reactor.run()语句,这让我失望了。是的,我很可能错过了一些基本的东西(这就是我在这里的原因)。
答案 0 :(得分:2)
您不需要更改运行反应堆的方式来实现此行为。
相反,只需认识到程序中所有是对某些事件的回应。
你什么时候发出一个愉快的长周末"通知?当然,当一个漫长的周末即将开始时。换句话说,日历(它只是一种特殊的计时设备)会生成一个事件并对其做出反应。您可以使用IReactorTime.callLater
实现此目的:计算下一个长周末和reactor.callLater(that_delay, some_function)
之前的时间。
如果您想在用户点击按钮时执行某些操作,那就是对GUI库生成的事件的响应。如果您想在连接USB设备时执行某些操作,那就是对平台HAL(或DBUS或udev)生成的事件的响应。
任何时候你认为自己采取行动并且#34;想一想为什么它在采取行动 - 在什么条件下或在什么情况下做出反应 - 并且你将要找出它实际上正在做出反应的事件。
答案 1 :(得分:1)
正如JP所说,反应堆回应了一个事件。 假设你在Linux / Unix系统上运行:
我已经努力获得一个异步的Twisted心态大约6个月了,我终于开始“搞定了”。这需要一段时间,但这是一次有价值的旅程。
对于某些人来说,学习扭曲就像80年代基于复古文本的冒险游戏之一,你或多或少地在实验中偶然发现,直到你发现一个吸引有用设备的魔术袋。那时事情变得容易了。
我发现研究扭曲的源代码非常有用,但是它有很多,知道从哪里开始或找到东西可能很有挑战性。代码往往组织良好,清晰,或多或少一致,这有助于。
另一个积极因素是那些非常参与Twisted(Glyph和JP只是其中两个)的人可以在这里提供帮助。
如果时间允许,我计划将一组示例服务器和客户端放在一起,这些服务器和客户端比现有的示例更多地使用扭曲的花哨。我希望在这样做之后,我可以让Twisted人员对他们进行评估,然后他们可能会考虑将其提供给其他人。
祝你扭曲的旅程好运
答案 2 :(得分:1)
你说过:
假设,一时兴起,我想......向所有客户发送友好信息
和
我想我想要做的就是在我坐在服务器上时用Python交互式生成事件。
我要将其转换为" 我希望在我的反应堆运行时有一个键盘界面"并举例说明。
在Twisted中,键盘只是你可以与所有其他IO一起使用的另一个IO接口,我将提供的示例是针对unix / posix类型的平台,尽管同样的想法当然可以在其他平台上实现操作系统。
(Disclamer:这个例子有点乱,因为它在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连接并等待密钥在stdin上发生的反应堆。键入密钥'将向所有连接的客户发送消息。
这是我经常用于扭曲应用程序的异步控制的方法,尽管它肯定只是其他答案中提到的众多方法之一。