3

我有一个父进程,它创建 2 个服务器套接字并调用select()它们以等待新连接。当连接到达时,一条消息被发送到一个子进程(fork()在服务器套接字创建之后用 创建,所以它们是共享的)。

在这个孩子中,调用accept()服务器套接字不起作用。我收到一个EAGAIN错误(非阻塞套接字)。accept()而在主进程中调用则完美无缺。

当然,我根本不调用accept()主进程,我只是测试一下它是否有效,它确实有效。

为什么我不能在父进程中调用accept()子进程?select()

编辑:这里的目标是创建固定数量的工作人员(比如说 8 个)来处理客户端连接,就像在 prefork 模型中一样。这些连接将是长连接,不像 HTTP。目标是负载平衡工作人员之间的连接。

为此,我使用了一个共享内存变量,其中包含一个工作人员当前连接的客户端的数量。我想“询问”客户端数量最少的工作人员来处理新连接。

这就是为什么我select()在父进程中执行,然后向子进程发送消息,因为我想“选择”哪个进程将处理新连接。

服务器侦听多个套接字(一个用于 ssl,一个不用于),这就是我使用select()而不是直接accept()在子进程中使用的原因,因为我不能accept()在我的子工作者中使用多个套接字。

4

1 回答 1

4

事实上,问题并不是我最初想的那样。以下是我为在工作进程之间的连接进行一些基本负载平衡所做的工作的回顾。

  • 一个主进程(父进程)创建 2 个服务器套接字,bind() 和 listen() 它们(例如有和没有 ssl)
  • 我用 fork() 创建了 8 个子进程,所以它们继承了父进程的套接字
  • 主进程select()无限循环运行
  • 当它的两个套接字中的一个可用时,它会通过管道向子节点发送消息。子进程由共享内存值确定,该值包含“子进程中”的当前客户端数量。选择当前处理最少数量的客户端的进程。
  • 这个子进程然后调用accept()服务器套接字(两者之间使用的套接字是在管道中传递的,所以子进程知道要调用哪一个accept()

问题是我的父进程告诉一个孩子接受套接字并立即重新进入循环,它select()再次运行。但如果孩子尚未接受套接字,则select()再次返回,以获得相同的连接。这就是为什么我得到一个 EAGAIN 错误,实际上我调用accept()了两次(或更多取决于速度-进程间竞争条件)!

解决方案是等待孩子在管道上回答诸如“嘿,我接受了连接,没关系!”之类的东西,然后返回select()循环。

这工作得很好。好奇的人可以在这里使用 Python 中的实现:https ://github.com/thibautd/Kiwi !

于 2012-04-13T23:27:55.550 回答