【问题标题】:How to properly set a flag in the write_fds and select() in C如何在 C 中的 write_fds 和 select() 中正确设置标志
【发布时间】:2016-06-15 14:36:06
【问题描述】:

send() 缓冲区已满时,我在给定套接字的 write_fds 中设置了一个标志,并且下一次迭代尝试通过检查是否设置了 write_fds 来发送它。

在 write_fds 中为一个套接字设置标志可以正常工作。但是,如果我为多个套接字执行FD_SET(i, write_fds),则只有最后一个套接字显示为已设置,并且只有最后一个套接字获取数据。

如果我在select(2) 之前执行write_fds = master;,那么它们都显示为已设置,并且所有未发送的数据都发送到所有套接字,但select 总是返回。

我确定我一定做错了什么。

FD_ZERO(&master);
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);

// socket setting...
// bind...
// listen...

FD_SET(listener, &master);
fdmax = listener; // so far, it's this one
for(;;){
    read_fds = master; // copy it
    // write_fds = master;
    select(fdmax+1, &read_fds, &write_fds, NULL, NULL);

    for(i = 0; i <= fdmax; i++){
        if(FD_ISSET(i, &read_fds)) {
            if(i == listener){
                addrlen = sizeof remoteaddr;
                newfd = accept(listener, (struct sockaddr * ) & remoteaddr, &addrlen);
                FD_SET(newfd, &master);
                if(newfd > fdmax)
                    fdmax = newfd;
                fcntl(newfd, F_SETFL, fcntl(newfd, F_GETFL, 0) | O_NONBLOCK);
            }else{
                // do some reading and then... send
                sent = send(i, buf, len, 0);
                if ((sent < 0 || (sent == -1 && errno == EWOULDBLOCK))
                    FD_SET(i, &write_fds);
            }  
        }  
        else if(FD_ISSET(i, &write_fds) && i != listener){
            if((sent = send(i, buf, len - sent, 0)) == len - sent)
                FD_CLR(i, &write_fds);
        }  
    }  
}

【问题讨论】:

标签: c sockets select nonblocking


【解决方案1】:

在调用 select 函数之前,您应该有 FD_ZEROFD_SETs。

例如

int res = 0;
for(;;){
     FD_ZERO(&read_fds);
     FD_ZERO(&write_fds);    

     fdmax = 0;
     size_t fd_index;
     for (fd_index=0; fd_index<num_of_fd; fd_index++)
     {
        FD_SET(fd_array[fd_index], &read_fds);  
        FD_SET(fd_array[fd_index], &write_fds);  

        if (fdmax < fd_array[fd_index])
           fdmax = fd_array[fd_index];
     }

    // write_fds = master;
    res = select(fdmax+1, &read_fds, &write_fds, NULL, NULL);

    if( res == 0 )
    {
       // TIMEOUT ...not your case
    }
    else if( res < 0 )
    {
        perror("Select error: ");
    }
    else
    {
        // process your data
    }

你不能写

read_fds = master;

因为fd_set 是一个复杂的结构体。

编辑

正如@jeremyP 评论的sent &lt; 0 应该是sent &gt; 0

【讨论】:

  • 他也不检查select()的结果。
  • 谢谢,我会调查的。
  • 同样检查send()的结果如果读取标志设置不正确,它应该读取if ((sent &gt; 0 ||...就目前而言,如果读取返回一个,它只会在写入时执行选择错误。
【解决方案2】:

在:

FD_SET(i, write_fds);

应该是:

FD_SET(i, &write_fds);

(注意与号)。

【讨论】:

  • 对不起,我在尝试简化实际代码以将其发布到此处时错过了这一点。设置为FD_SET(i, &amp;write_fds);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-28
  • 2011-07-21
  • 1970-01-01
  • 2022-09-30
  • 2011-03-30
  • 2022-11-01
  • 1970-01-01
相关资源
最近更新 更多