Ruby中的poll()?

时间:2009-04-07 15:29:39

标签: ruby networking sockets

我目前正在将自编写的网络应用程序从C ++移植到Ruby。此网络应用程序通常需要同时管理大约10,000个套接字,这意味着它需要快速访问具有可读数据,传入连接等的任何套接字。

我在用C ++编写时已经遇到过,select()在这种情况下不起作用,因为在内部它使用32 DWORD s(128字节)来管理最多1024个带有位掩码的套接字。由于我有时需要使用超过10,000个插槽,因此这个功能还不够。因此,我不得不切换到poll(),这也使代码更加优雅,因为我并不总是再次添加和删除所有文件描述符。

正如我从Ruby文档中看到的那样,Ruby提供了IO.select(),它基本上是C-API的包装器(据我所知)。不幸的是,似乎没有IO.poll(),我需要这个特定的应用程序。

IO.select()与WinSocks和Berkeley套接字上的select()具有相同的限制吗?如果是的话,有办法解决这个问题吗?

3 个答案:

答案 0 :(得分:2)

选择无法安全地用于Linux系统上具有1024个以上文件描述符的程序。这是因为select系统调用使用的底层fd_set是一个固定大小的缓冲区,即它的大小是在编译时分配的,而不是在运行时分配的。

从男人2中选择:

int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);
  

fd_set是固定大小的缓冲区。执行FD_CLR()或   FD_SET(),其值为fd,为负或等于或   大于FD_SETSIZE将导致未定义的行为。   而且,POSIX要求fd是有效的文件描述符。

这意味着如果程序中有超过1024个文件描述符,并且使用select系统调用,则最终会导致内存损坏。

如果您想在程序中使用超过1024个文件描述符,必须使用poll或epoll,并确保您永远不会使用select,否则您将获得随机内存损坏。如果您使用ulimit,则通过select更改文件描述符表的大小非常危险。不要这样做。

Ruby的select似乎实际上是通过select系统调用实现的,所以虽然它看起来像增加ulimit的工作,但是发生了腐败: https://github.com/ruby/ruby/blob/trunk/thread.c

此外,ruby中的一些不相关的API似乎使用select(请参阅thread_pthread.c),因此使用它们或使用大于1024的文件描述符表运行的ruby程序中使用这些API的任何代码也可能不安全。

答案 1 :(得分:1)

IO.select()的限制以及实际上每个进程可以拥有的打开连接数似乎主要由底层操作系统支持决定。绝对没有固定的1024个套接字限制。

例如,在WinXP下,我最多打开69个套接字(甚至在我选择之前)。我确信这可能是可调的,我只是不知道如何。

在Linux下,限制是允许的打开文件数。默认情况下,限制通常为1024(运行ulimit -a来检查)。

但是,您可以轻松更改此项,例如ulimit -n 10000。 我刚刚运行了一个测试,并愉快地使用TCPSocket.new创建的1024个活动套接字,并使用IO.select来测试就绪数据。

注意:这个GServer article中有一个很好的IO.select用法示例。

答案 2 :(得分:0)

IO::Reactor可能会满足您的需求。它有一个类似于你所描述的轮询方法。