【问题标题】:Increasing limit of FD_SETSIZE and select增加 FD_SETSIZE 的限制并选择
【发布时间】:2011-12-20 01:19:47
【问题描述】:

我想为我的系统增加 FD_SETSIZE 宏值。 有什么办法可以增加 FD_SETSIZE 这样选择就不会失败了

【问题讨论】:

  • 是的,就我而言,我需要它大约 2048 。有什么办法可以设置吗?
  • 因为我想增加我的服务器限制以支持这么多的连接。
  • 无意冒犯,但考虑增加FD_SETSIZE 是一件非常愚蠢的事情。 2048 个并发连接(或更确切地说,更多)正好在 epoll_wait 大大优于 selectpoll 的范围内,因为它不需要复制 8 KB 的数据每次都不需要迭代超过两千个描述符。
  • 真正的答案是:NO 不在 linux 下。对于 BSD 和 Windows,可以重新定义 FD_SETSIZE。试图做到这一点需要黑客攻击,它肯定会导致未来的问题。因此,当最大描述符值可以超过 1024 时,更喜欢使用 poll。

标签: c linux file-descriptor


【解决方案1】:

按照标准,没有办法增加FD_SETSIZE。一些程序和库(想到 libevent)试图通过为fd_set 对象分配额外空间并将大于FD_SETSIZE 的值传递给FD_* 宏来解决这个问题,但这是一个非常糟糕的主意,因为健壮的实现可以对参数执行边界检查,如果超出范围则中止。

我有一个应该始终有效的替代解决方案(即使标准没有要求)。不要使用单个 fd_set 对象,而是分配一个足够大的数组以容纳您需要的最大 fd,然后使用 FD_SET(fd%FD_SETSIZE, &fds_array[fd/FD_SETSIZE]) 等来访问该集合。

【讨论】:

  • @dns:那是虚假文件。 :-) 请阅读pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html。好吧,开个玩笑,请解释一下您认为我的回答“错误”的地方。
  • 按照微软自己的“根据标准,没有办法增加 FD_SETSIZE”是错误的,因为我逐字引用微软自己:“这个值用于构造 fd_set 结构在 select() 中使用。WINSOCK.H 中的默认值为 64。如果应用程序被设计为能够使用超过 64 个套接字,请在包含 WINSOCK.H 之前在每个源文件中定义清单 FD_SETSIZE。"请阅读support.microsoft.com/kb/111855
  • 好吧,为了符合“标准”,您也可以在 Linux/unix/mac 变体上通过简单地更改 #define __FD_SETSIZE 1024 以下 2 个文件 /usr/include/bits/typesizes 来增加它.h /usr/include/linux/posix_types.h 但是你说你不能增加它,你可以这样,无论哪种方式答案都是错误的
  • 这也不是标准的。这是一个特定于实现的 hack。我同意在许多实现中,您可以对这种形式进行特定于实现的 hack,但根据标准它是不正确的。
  • @AndrewHacking:人们何时会厌倦在此发布错误的 cmets?是的,一些实现允许它。不,根据接口的规范,它是无效的。相关文字是……
【解决方案2】:

如果可能,我还建议使用poll。并且存在几个“事件”处理库,如 libeventlibev(或来自 GTK 的 GlibQtCore 等的事件能力)应该可以帮助你。还有像epoll 这样的东西。而你的问题与C10k有关

【讨论】:

  • 是的。我认为这是最终的答案。如果您的监控描述符之一在 linux 下超过 1024,则您必须通过 fd_set 结构进行 HACK(并且无论如何都会冒进一步的问题),或者使用 poll what is ... 更好。
  • 你必须祈祷你使用的每一个图书馆都能正确地做到这一点。使用 1024 个句柄或 100% 了解您的程序代码(包括所有库)并确保从不使用“选择”的唯一有效解决方案。
【解决方案3】:

实际上有 IS 一种在 Windows 上增加 FD_SETSIZE 的方法。它在 winsock.h 中定义,并且每个 microsoft 自己都可以通过在包含 winsock.h 之前简单地定义它来增加它

http://support.microsoft.com/kb/111855

我一直这样做,没有任何问题我使用的最大价值是我正在开发的服务器的 5000 左右

【讨论】:

  • BSD 和 Windows 允许设置 FD_SETSIZE。不是 Linux,其中 fd_set 内部大小实际上是由硬编码为 1024 的 __FD_SETSIZE 设置的。对于 linux,最好使用 poll,因为 slecet 不能用于超过前 1024 个描述符。事实上,它似乎可以在 linux 上工作,但会使用分配的 fd_set 之外的位,这肯定会破坏堆栈并导致崩溃。这就是为什么当前的答案是在堆栈上为自己分配更多不太漂亮的位置。
  • 这个问题涉及的是 linux,而不是 windows。
  • 您的链接已失效。你能提供一个新的吗?
  • 这里也提到了:docs.microsoft.com/en-us/windows/win32/api/winsock2/…(ctrl+f 'FD_SETSIZE')
【解决方案4】:

用 poll 代替会更好(也更容易)。通常 poll() 是 select() 的简单替代品,不受 FD_SETSIZE 的 1024 限制...

fd_set fd_read;
int id = 42;
FD_ZERO(fd_read);
FD_SET(id, &fd_read);
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
if (select(id + 1, &fd_read, NULL, NULL, &tv) != 1) {
   // Error.
}

变成:

struct pollfd pfd_read;
int id = 42;
int timeout = 5000;
pfd_read.fd = id;
pfd_read.events = POLLIN;
if (poll(&pfd_read, 1, timeout) != 1) {
   // Error
}

您需要为 pollfd 结构包含 poll.h。

如果您需要读写,则将事件标志设置为 POLLIN |民意调查。

【讨论】:

    【解决方案5】:

    为了使用大于 FD_SETSIZE 的fd_set,可以像这样定义一个扩展的:

    #include <sys/select.h>
    #include <stdio.h>
    
    #define EXT_FD_SETSIZE 2048
    typedef struct
    {
        long __fds_bits[EXT_FD_SETSIZE / 8 / sizeof(long)];
    } ext_fd_set;
    
    int main()
    {
        ext_fd_set fd;
        int s;
        printf("FD_SETSIZE:%d sizeof(fd):%ld\n", EXT_FD_SETSIZE, sizeof(fd));
        FD_ZERO(&fd);
        while ( ((s=dup(0)) != -1) && (s < EXT_FD_SETSIZE) )
        {
            FD_SET(s, &fd);
        }
        printf("select:%d\n", select(EXT_FD_SETSIZE,(fd_set*)&fd, NULL, NULL, NULL));
        return 0;
    }
    

    这打印:

    FD_SETSIZE:2048 sizeof(fd):256

    选择:2045


    为了打开超过 1024 个文件描述符,需要使用例如 ulimit -n 2048 来增加限制。

    【讨论】:

    • 这有潜在的危险。如果不涉及(有效的,IMO)标准合规性问题,有一个更明显的用例可能会失败,那就是在链接到编译为使用系统定义的 FD_SETSIZE 的库时。使用poll() 是正确的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-27
    • 2013-08-25
    • 2014-08-08
    相关资源
    最近更新 更多