【问题标题】:Passing Python object to another Python process将 Python 对象传递给另一个 Python 进程
【发布时间】:2016-06-23 12:56:32
【问题描述】:

假设我们有一个用 Python 编写的服务器应用程序。

假设这个主服务器进程在启动时又分叉了两个进程。

服务器等待它的客户端,当客户端到来时决定两个分叉进程中的哪一个应该通过客户端的套接字。

我不想在每次客户到来时都派生一个进程;我想拥有固定数量的服务器,但一个主服务器接收连接,然后将其传递给处理特定工作客户端请求的服务器。

这应该是DOS攻击防护、作业分离等等等等。

在启动的 Python 程序之间传递 Python 对象有什么技巧吗?

一些共享内存或类似的东西?

酸洗套接字对象并通过 IPC 推送它会起作用吗?

【问题讨论】:

  • 我认为您不能(或不应该)序列化诸如套接字之类的东西。为什么不使用同步/事件架构?
  • 就是这样。序列化它应该不是问题等等。但是套接字对象是一半 C 一半 Python,所以在这个过程中可能会发生任何事情,这肯定是不稳定的。
  • @Dalen,我不知道这样做是否正确,但我能够通过以下 sn-ps 共享任意对象(甚至是远程): stackoverflow.com 不过,我对安全性/稳定性/性能一无所知。在你的情况下(使用套接字)我不会尝试将它们变成远程共享对象,但你可以从链接并将其应用到其他地方,也许。
  • @krysopath :谢谢,但我以前做过这样的事情,甚至更疯狂。远程共享套接字是不可能的。如果您想将连接转发到另一台 PC,有很多方法,但防火墙反对真正的切换,而且它复杂到无用的地步。 IE。告诉客户端重定向到另一个 IP 很容易。
  • @Dalen 是的,确实:远程共享套接字正在破坏套接字的目的 :) 我只是认为这种在进程之间共享对象的方法可以帮助您进行工作分离等。我能够滥用 sn-p 来实现在 localhost 上运行的“信息代理”,它被另一个 localhost 进程询问,但只回答有效请求。它可能达不到你的目的。

标签: python sockets object ipc


【解决方案1】:

酸洗套接字对象并通过 IPC 推送它会起作用吗?

没有。该对象内部是内核套接字的文件描述符或句柄。它只是进程在进行系统调用时用来识别套接字的一个数字。

如果您选择该 Python 套接字对象并将其发送到另一个进程,该进程将使用它未打开的套接字的句柄。或者更糟糕的是,该句柄可能指向不同的打开文件。

处理这个问题的最有效方法(在 Linux 上)是这样的:

  • 主进程打开监听套接字(例如 TCP 端口 80)
  • 主进程派生 N 个子进程,他们都继承打开的套接字
  • 他们都调用accept() 并阻塞,等待新的连接
  • 当一个新的客户端连接时,内核将选择一个具有该套接字句柄的进程来接受连接;其他人将继续等待

这样,您就可以让内核处理负载平衡。

如果您不希望这种行为,一种方法(在 UNIX 中)可以将打开的套接字传递给另一个进程。同样,这不仅仅是手柄;内核有效地将打开的套接字复制到进程的打开文件列表中。这种机制称为SCM_RIGHTS,您可以在此处查看示例(C 语言): http://man7.org/tlpi/code/online/dist/sockets/scm_rights_send.c.html

否则,您的主进程将需要有效地代理与子进程的连接,从而降低系统的效率。

【讨论】:

  • 是的,是的,我知道,但如果你能以某种方式强制一个套接字进入共享内存,那么它实际上是否是同一个套接字。我认为应该可以在进程之间共享句柄,至少在 Unix 上是这样,因为当您使用打开的 PIPE 分叉一个进程时会发生这种情况。还有其他想法吗?
  • 您可以做的是解析请求并通过单独的节点进行处理。您可以尝试使用一些排队机制(kombu 等)并通过此管道发送序列化对象。这将使您的两个组件保持足够分离,以防其中一个组件发生故障,第二个组件可以继续运行并处理这些请求,并且通过队列进行通信非常简单。享受吧!
  • @daTokenizer :绝对是我不想做的事情。每个进程都必须解析标头并决定如何处理它们。主进程甚至不能回答客户。只需决定将连接转发到哪里。
  • 第一个解决方案,让内核决定哪个进程获得连接是非常好的技巧。它确定有效吗?问题是,我已经强制内核使用 select() 检查并重新检查打开的套接字。所以这可能有点过头了——一遍又一遍地检查每个进程中的每个套接字的 read() write() 就绪性。
  • 我的服务器是异步和线程客户端处理的混合体。 IE。有些事情像在 asyncore.py 中一样处理,有些事情是通过线程推送的,因此客户端很复杂,但它提高了效率,按原样滥用内核并将太长的作业推送到线程中,同时在 asyncore.loop() 之类的东西中处理快速的作业立刻。此外,客户端无法杀死它,无论它做什么以及响应方法中的任何错误。所以你的第二种方法应该可以解决问题。但我担心这一切可能会导致系统调用过多而变得繁重。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-15
  • 2018-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多