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_fds
和 except_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()
.
中循环之外的任何操作
我在套接字 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_fds
和 except_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()
andpselect()
functions will fail if:...
EINVAL
Thenfds
argument is less than0
or greater thanFD_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()
.