Twisted - 传递协议(和套接字句柄)对象到Twisted子进程

时间:2014-09-19 10:50:06

标签: python sockets multiprocessing twisted

使用以下代码,我似乎可以使用multiprocessing.reduction在子进程中轻松地重建套接字。

import socket,os
import multiprocessing
from multiprocessing.reduction import reduce_handle, rebuild_handle

client = socket.socket()
client.connect(('google.com', 80))

rd = reduce_handle(client.fileno())

print "Parent: %s" % (os.getpid())

def test(x):
        print "Child: %s" % (os.getpid())

        build = rebuild_handle(x)
        rc = socket.fromfd(build, socket.AF_INET, socket.SOCK_STREAM)
        rc.send('GET / HTTP/1.1\n\n')
        print rc.recv(1024)

p = multiprocessing.Process(target=test, args=(rd,))
p.start()
p.join()

我有一个Twisted游戏服务器,可以同时运行多个匹配项。这些匹配可能包含多个玩家,每个玩家都有一个协议实例。我想要做的是在Twisted子进程池中分配匹配,并让池处理他们自己处理的匹配的客户端。看起来像读/写客户端的数据并将数据传递到子进程和从子进程传递数据似乎是不必要的开销。

协议保证是TCP实例,所以我相信我可以(像上面的代码一样)减少套接字:

rd = reduce_handle(myclient.transport.fileno())

通过查看Twisted源将数据传递给子进程,似乎我可以在子进程中重建它,如下所示:

import socket
from twisted.internet import reactor, tcp
from multiprocessing.reduction import reduce_handle, rebuild_handle

handle = rebuild_handle(rd)
sock = socket.fromfd(handle, socket.AF_INET, socket.SOCK_STREAM)
protocol = MyProtocol(...)
transport = tcp.Connection(sock, protocol, reactor=reactor)
protocol.transport = transport

我会尝试这个,但看到我对Twisted内部结构并不是非常熟悉,即使这有效,我也不知道其含义是什么。

有谁能告诉我这看起来是否正确以及它是否有效?由于某种原因,这是不可取的(我从来没有在Twisted文档或帖子中提到它,即使它看起来很相关)?如果这有效,我应该警惕什么?

提前致谢。

1 个答案:

答案 0 :(得分:2)

Twisted和多处理模块彼此不兼容。如果代码似乎有用,那只是运气和意外以及未来版本的任何一个(可能没有未来的多处理版本,但可能会有扭曲的期货版本)可能会把这个好运变成坏事运气。

twisted.internet.tcp也不是一个在您的应用程序中使用的好模块。它并不完全是私有的,但您也不能依赖它始终与您的应用程序使用的反应器一起工作。例如,iocp反应器使用twisted.internet.iocpreactor.tcp而不会与twisted.internet.tcp一起工作(我不希望你很可能会使用iocp反应器代码和其他反应堆Twisted ship with do twisted.internet.tcp但第三方反应堆可能没有,Twisted的未来版本可能会改变反应堆的实施方式。)

您要解决的问题有两部分。一部分是在两个进程之间传递文件描述符。另一部分是说服反应堆开始监控文件描述符并调度其事件。

multiprocessing.reduction与Twisted一起使用的风险可能很小,因为它似乎与该模块中的流程管理无关。相反,它只是关于酸洗插座。因此,您可以继续使用该方法传达文件描述符(如果您因为某些原因希望避免在父进程中使用Twisted,您可能希望这样做 - 我不确定,但它没有&# 39;听起来像这样的情况)。但是,替代方法是使用twisted.python.sendmsg通过UNIX套接字传递这些描述符 - 或者更好的是,使用更高级别的层来处理繁琐的sendmsg位:{{1 }}。 AMP支持作为文件描述符的参数类型,允许您在进程之间传递文件描述符(同样,仅通过UNIX套接字),就像您传递任何其他Python对象一样。

对于第二部分,您可以使用twisted.protocols.amp向反应堆添加已建立的TCP连接。这是一个你可以依赖的公共接口(只要反应堆实际上实现了它 - 并非所有反应堆都能这样做:如果你想做某种优雅的降级或用户,你可以使用reactor.adoptStreamConnection反省反应堆。友好的错误报告)。