Solaris 上的 C 套接字 select 错误

C Socket select error on Solaris

我在套接字 select 上得到一个 return 的 -1。然而,这只会在我们使用新安装的 sybase 数据库时发生。将此代码与旧数据库一起使用,我没有收到任何套接字 select 错误,一切正常。

在下面的示例中 how_many = 2,并且 timeout_secs = 60。

重要的是要注意,在下面的代码中,当它工作时 file_limits.rlim_cur 是 256。但是对于新数据库 file_limits.rlim_cur = 超过 65,000 和套接字 select return小号 -1。我已经尝试将 select 中的第一个参数硬编码为 256 但它仍然是 returns -1.

int socket_activity( int how_many, int *fd, int timeout_secs )
{
int                                 i;
int                                 select_fd;
fd_set                              read_fds;
fd_set                              except_fds;
struct timeval              timeout;
struct rlimit               file_limits;

/*
** Determine the current limits.
*/

if ( getrlimit( RLIMIT_NOFILE, &file_limits ) != 0 )
    return( -1 );

/*
** Set up the select structures.  Initialize the timeout to the specified
** seconds.  Only non-negative file descriptors are initialized.
*/

FD_ZERO( &read_fds );
FD_ZERO( &except_fds );
for ( i = 0; i < how_many; i++ )

    if ( fd[i] >= 0 ) {

        FD_SET( fd[i], &read_fds );
        FD_SET( fd[i], &except_fds );

    }  /*  of if  */

timeout.tv_sec  = timeout_secs;
timeout.tv_usec = 0;

/*
** Perform the select and check on the results.
*/

select_fd = select( file_limits.rlim_cur,
                    &read_fds,
                    NULL,
                    &except_fds,
                    &timeout );

if ( select_fd > 0 ) {

    /*
    ** Scan the list of file descriptors and return which file
    ** descripitor show activity.  Only check non-negative file descriptors.
    */

    for ( i = 0; i < how_many; i++ )
        if ( ( fd[i] >= 0 ) &&
             ( FD_ISSET( fd[i], &read_fds ) ) )
            return( fd[i] );

    /*
    ** No file descriptor showed activity so return zero to indicate
    ** that a timeout occured.
    */

    return( 0 );

}  /*  of if  */

else

    /*
    ** Simply return the return value from select (the function will
    ** return a 0 on timeout or a -1 on error).
    */

    return( select_fd );

}  /*  of function  */

您确实需要 post an MCVE 才能获得真正的帮助。因此,这是更明智的猜测,而不是实际答案。

首先,假设您要传递一个指向 int 打开文件描述符数组的 int *,这是无用的:

/*
** Determine the current limits.
*/

if ( getrlimit( RLIMIT_NOFILE, &file_limits ) != 0 )
    return( -1 );

如果您通过了已经打开的文件描述符,则打开描述符数量的资源限制完全无关紧要 - 描述符已经打开,如果有什么要打开的降低限制,您可能无法对某些描述符进行操作。

其次,如果打开文件的限制大于FD_SETSIZE中的值,这是有问题的。您传递给 select - read_fdsexcept_fds 的数组 - 每个最多有 FD_SETSIZE 个元素:

select_fd = select( file_limits.rlim_cur,
                    &read_fds,
                    NULL,
                    &except_fds,
                    &timeout );

我不知道您的 Solaris 安装上的 FD_SETSIZE 是什么,但鉴于您在问题中发布的 "the code below when it works file_limits.rlim_cur is 256",我强烈怀疑这就是正在发生的事情。鉴于 Solaris select(3C) man page 的内容是

Errors

The select() and pselect() functions will fail if:

...

EINVAL The nfds argument is less than 0 or greater than FD_SETSIZE.

您需要修复代码。

这将导致数组后面的描述符饥饿:

for ( i = 0; i < how_many; i++ )
    if ( ( fd[i] >= 0 ) &&
         ( FD_ISSET( fd[i], &read_fds ) ) )
        return( fd[i] );

您总是 return 您找到的第一个带有 activity 的描述符。如果阵列中的第一个总是忙,它是唯一一个将得到服务的。

您还忽略了 except_fds。如果其中一个 "goes bad" 以其他描述符永远不会有可读数据的方式存在,那么您的代码将停止执​​行除在 select().

中循环之外的任何操作