select 和 receivefrom 出现意外结果

发布于 2024-11-01 18:58:45 字数 1573 浏览 11 评论 0原文

fd_set rset;
struct timeval tv;
FD_ZERO(&rset);
FD_SET(sockfd, &rset);
tv.tv_sec = 1;
tv.tv_usec = 0;

for(;;)
{
  for(count = 0; count < elements in sockaddr_in array; count++)
  {
    //flag_array is filled with -1 before for(;;)
    if(flag_array[count] == -1 && select(sockfd+1, &rset, NULL, NULL, &tv))
    {
      recvfrom(...)
    }
    tv.tv_sec = 1;
    FD_ZERO(&rset);//this fixed it
    FD_SET(sockfd, &rset);//and this too
  }

  //contact everyone from sockaddr array (works like a charm!)
}

如果在发生“超时”之前我没有将消息从其他程序发送到该程序,则 select 语句将“失败”,因此我无法在其中使用 recvfrom 语句。我曾经这样做过,以便我的另一个程序在无限循环中联系这个程序,它从未进入 if 语句内部。

有什么作用: 如果我在每次超时发生之前联系该程序,一切都会很好。 如果我将 recvfrom 语句放在 if(___ && select) 之外,它就完全可以正常工作。

这是一个小图,该程序将被称为 Recv:

if(A contacts Recv before timeout)    count = 0
   Recv stores contact A in struct
if(B contacts Recv before timeout)    count = 1
   Recv stores contact B in struct
if(timeout)                           count = 2

if(C contacts Recv after timeout)     count = 3
   nothing
                                      count = 4

该程序将很好地联系 A 和 B //在发布此内容之前 2 分钟回到循环开始

flag_array == -1 is false             count = 0
flag_array == -1 is false             count = 1
flag_array == -1 is true...select "fails" count = 2..3..4..(exit loop)

我决定最后看一下我以前的代码。我想我

FD_ZERO(&rset);
FD_SET(sockfd, &rset);

在 for 循环(其中 tv.tv_sec = 1)之后忘记了。

有人可以详细说明为什么有必要这样做吗?

fd_set rset;
struct timeval tv;
FD_ZERO(&rset);
FD_SET(sockfd, &rset);
tv.tv_sec = 1;
tv.tv_usec = 0;

for(;;)
{
  for(count = 0; count < elements in sockaddr_in array; count++)
  {
    //flag_array is filled with -1 before for(;;)
    if(flag_array[count] == -1 && select(sockfd+1, &rset, NULL, NULL, &tv))
    {
      recvfrom(...)
    }
    tv.tv_sec = 1;
    FD_ZERO(&rset);//this fixed it
    FD_SET(sockfd, &rset);//and this too
  }

  //contact everyone from sockaddr array (works like a charm!)
}

If I don't send my message from my other program to this program before a "timeout" occurs, the select statement "fails", so I can't use the recvfrom statement inside of it. I once made it so that my other program contacts this one on an infinite loop, it never went inside of the if statement.

What does work:
If I contact this program before each timeout occurs, everything is fine.
If I put the recvfrom statement outside of the if(___ && select), it works completely fine.

Here's a little diagram where this program is going to be called Recv:

if(A contacts Recv before timeout)    count = 0
   Recv stores contact A in struct
if(B contacts Recv before timeout)    count = 1
   Recv stores contact B in struct
if(timeout)                           count = 2

if(C contacts Recv after timeout)     count = 3
   nothing
                                      count = 4

the program will contact A and B just fine
//goes back to start of loop

flag_array == -1 is false             count = 0
flag_array == -1 is false             count = 1
flag_array == -1 is true...select "fails" count = 2..3..4..(exit loop)

2 minutes before posting this I decided to take one last look at my previous code. I guess I forgot

FD_ZERO(&rset);
FD_SET(sockfd, &rset);

after the for loop (where tv.tv_sec = 1) is at.

Can someone elaborate on why it's necessary to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

燃情 2024-11-08 18:58:45

select() 修改传递的fd_set - 您必须在每次调用select()之前对其进行设置。这就是 select() 应该如何工作的。

select() modifies the passed fd_set - You have to set it up before each call to select(). This is just how select() should work.

土豪我们做朋友吧 2024-11-08 18:58:45

这是必要的,因为 select() 可能会修改文件描述符集。

引用 select(3) 的 Linux 手册页

成功完成后,pselect() 或 select() 函数应修改 readfds、writefds 和 errorfds 参数指向的对象,以指示哪些文件描述符已准备好读取、准备写入或有错误情况分别待处理,并应返回所有输出集中就绪描述符的总数。对于小于 nfds 的每个文件描述符,如果在输入时设置了相应位并且该文件描述符的相关条件为真,则应在成功完成时设置相应位。

请注意,select() 还可以修改其struct timeval 参数,例如Linux 在其中存储经过的时间。因此,您还应该重置 tv 的所有字段。

It's necessary because select() may modify the file descriptor sets.

Citing from the Linux manpage for select(3):

Upon successful completion, the pselect() or select() function shall modify the objects pointed to by the readfds, writefds, and errorfds arguments to indicate which file descriptors are ready for reading, ready for writing, or have an error condition pending, respectively, and shall return the total number of ready descriptors in all the output sets. For each file descriptor less than nfds, the corresponding bit shall be set on successful completion if it was set on input and the associated condition is true for that file descriptor.

Note that select() may also modify its struct timeval argument, e.g. Linux stores the elapsed time in it. Thus, you should reset all fields of tv as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文