当前位置: 首页 > 面试题库 >

在fd_set上使用结构复制(对于select()或pselect())会导致问题的平台吗?

邢运良
2023-03-14
问题内容

select()pselect()系统调用修改其参数(在“
fd_set *”参数),所以输入值告诉系统文件描述符检查和返回值告诉程序员哪些文件描述符当前可用它。

如果要为同一组文件描述符重复调用它们,则需要确保每个调用都有一个描述符的新副本。显而易见的方法是使用结构副本:

fd_set ref_set_rd;
fd_set ref_set_wr;
fd_set ref_set_er;
...
...code to set the reference fd_set_xx values...
...
while (!done)
{
    fd_set act_set_rd = ref_set_rd;
    fd_set act_set_wr = ref_set_wr;
    fd_set act_set_er = ref_set_er;
    int bits_set = select(max_fd, &act_set_rd, &act_set_wr,
                          &act_set_er, &timeout);
    if (bits_set > 0)
    {
        ...process the output values of act_set_xx...
    }
 }

(已 编辑以删除不正确的struct fd_set引用-如“ R ..”所指出。

我的问题:

  • 是否存在不安全地复制fd_set所示值的结构的平台?

我担心,以免存在隐藏的内存分配或类似的意外情况。(有宏/功能FD_SET(),FD_CLR(),FD_ZERO()和FD_ISSET()可以掩盖应用程序的内部结构。)

我可以看到MacOS X(Darwin)是安全的;因此,其他基于BSD的系统可能是安全的。您可以通过记录已知在答案中安全的其他系统来提供帮助。

(我确实不太关心它fd_set与8192个以上打开文件描述符的配合情况-默认打开文件的最大数量仅为256个,但最大数量为“无限制”。而且,由于结构为1
KB,因此复制代码的效率并不高,但是在每个循环中遍历文件描述符列表来重新创建输入掩码也不一定有效,也许select()当打开了这么多文件描述符时您就无法执行,尽管那是当您最有可能需要此功能。)

有一个相关的SO问题-询问[“ poll()vsselect()”],它解决了与此问题不同的一系列问题。

请注意,在MacOS X(大概是BSD)上,有一个FD_COPY()带有有效原型的宏或函数:

  • extern void FD_COPY(const restrict fd_set *from, restrict fd_set *to);

在尚不可用的平台上,可能值得进行仿真。


问题答案:

由于structfd_set这只是一个常规的C结构,因此应该总是可以的。我个人不喜欢通过=运算符进行结构复制,因为我在许多无法访问正常的编译器内在函数的平台上工作。memcpy()在我的书中,显式使用而不是让编译器插入函数调用是一种更好的方法。

在C规范中,第 6.5.16.1 节“ 简单赋值” (为简便起见,在此处进行了编辑):

以下条件之一应成立:

  • 左操作数具有与右类型兼容的结构或联合类型的合格或不合格版本;

简单赋值 (=)中,将右操作数的值转换为赋值表达式的类型,并替换存储在由左操作数指定的对象中的值。

如果从另一个对象中读取存储在一个对象中的值,而该对象与第一个对象的存储有任何重叠,则该重叠应准确无误,并且两个对象应具有兼容类型的合格或不合格版本;否则,行为是不确定的。

因此,只要您struct fd_set实际上是一个常规Cstruct,您就可以保证成功。但是,它的确取决于编译器发出某种代码来执行此操作,或者取决于memcpy()它用于结构分配的任何内在函数。如果您的平台由于某种原因无法链接到编译器的内部库,则可能无法正常工作。

如果您打开的文件描述符数量多于文件描述符的数量,则您将需要技巧struct fd_set。linux
手册页说:

An
fd_set是固定大小的缓冲区。执行FD_CLR()FD_SET()具有值fd为负或等于或大于FD_SETSIZE将导致未定义的行为。此外,POSIX必须fd是有效的文件描述符。

如下所述,证明您的代码在所有系统上都是安全的可能并不值得。 FD_COPY()提供此类用途,并且可以保证始终保证:

FD_COPY(&fdset_orig, &fdset_copy)用的&fdset_copy副本替换已分配的文件描述符集&fdset_orig



 类似资料:
  • 文件句柄管理 更多... 成员变量 unsigned char  fd_bits [(FD_SETSIZE+7)/8]   数组,每一个数组元素都能与一打开的文件句柄(socket、文件、管道、设备等)建立联系   详细描述 文件句柄管理 示例: tcpclient_select_sample.c.

  • 所以我添加了一些属性,然后停止了其中一个节点,会话复制成功。 但是当我用hibernate+spring mvc+spring security将这个配置移到我的应用程序中时,当我尝试登录时,我总是得到异常 我的所有会话对象都实现了可序列化接口,在web.xml中我已经添加了,我尝试过让EntityManager字段瞬态化,但没有帮助。我认为可能是spring试图将一些bean保存到session

  • 我正在试着检查用户是在Iphone上还是在Android上 当我注释这行代码时,应用程序运行良好

  • 问题内容: 我是Android新手。似乎仅是日蚀和SDK安装程序就已经存在太多问题了。我一直在研究Android开发人员网站上的示例,但它抛出一个错误: 导入android.support无法解析 我正在尝试导入以下内容: 我安装了三个最新的SDK平台版本,还安装了rev.10支持库。android.jar文件指向错误的文件夹吗?我找到了要导入的文件夹/文件,但我想知道它们是否在正确的位置。 C:

  • 每次我试图在谷歌云平台上启用谷歌广告API时,我都会收到以下错误: 未找到服务名称为googleads的API解决方案。古格里皮斯。通用域名格式 我在同一封电子邮件下设置了一个广告管理器帐户,并生成了一个API访问令牌。我尝试在不同的电子邮件和不同的浏览器下设置它,我甚至尝试使用隐身模式,看看这是否会根据其他线程的指令解决问题。我还为我试图访问谷歌广告api的项目创建了oAuth2凭据。 我真的只

  • 问题内容: 在我的应用程序中,有一个io线程,专用于 用自定义协议包装从应用程序收到的数据 通过TCP / IP发送数据+自定义协议数据包 通过TCP / IP接收数据+自定义协议数据包 解包自定义协议并将数据传递给应用程序。 应用程序通过不同的线程处理数据。此外,要求还规定未确认的窗口大小应为1,即随时都应只有一条待处理的未确认消息。这意味着,如果io- thread在套接字上调度了一条消息,它