我有一个单线程程序。它每五秒钟向四个目的地发送消息。我不希望connect()
被阻止。所以我正在写这样的程序:
int j, rc, non_blocking=1, sockets[4], max_fd=0;
struct sockaddr server=get_server_addr();
fd_set fdset;
const struct timeval conn_timeout = { 2, 0 }; /* 2 seconds */
for (j=0; j<4; ++j)
{
sockets[j]=socket( AF_INET, SOCK_STREAM, 0 );
ioctl(sockets[j], FIONBIO, (char *)&non_blocking);
connect(sockets[j], &server, sizeof (server));
}
/* prepare fd_set */
FD_ZERO ( &fdset );
for (j=0;j<4;++j)
{
if (sockets[j] != -1 )
{
FD_SET ( sockets[j], &fdset );
if ( sockets[j] > max_fd )
{
max_fd = sockets[j];
}
}
}
rc=select(max_fd + 1, NULL, &fdset, NULL, &conn_timeout );
if(rc > 0)
{
for (j=0;j<4;++j)
{
if(sockets[j]!=-1 && FD_ISSET(sockets[j],&fdset))
{
/* send() */
}
}
}
/* close all valid sockets */
但是,似乎select()
在ONE文件描述符准备就绪后立即返回,而不是阻塞conn_timeout
(2秒)。那么在这种情况下我如何实现目标?
答案 0 :(得分:4)
是的,select
的设计假设您希望在每个套接字准备就绪后立即为其提供服务。
如果我理解你要做的事情,那么实现它的最简单方法是在fdset准备就绪时从fdset中删除每个套接字。如果设备中还有任何套接字,请使用gettimeofday
向下调整超时,然后再次呼叫select
。当该集合为空时,所有四个套接字都可用,您可以继续。
答案 1 :(得分:1)
有三种基本方法:
如果您希望保持严格的便携性,则需要进行迭代:
select()
如果您希望保持便携性,但可以使用线程:
如果您不需要携带:大多数操作系统都有适合这种情况的工具,例如: Windows / .NET具有WaitAll(与异步发送和事件一起)
答案 2 :(得分:0)
我没有看到您声明的目标与您声明的问题之间存在关联。你说select()阻塞直到至少有一个套接字准备就绪是正确的,但根据上面的目标#2,这正是你想要的。在所有四个套接字同时就绪之前,你所声明的目标中没有任何关于阻塞的内容。
您还应该注意,套接字几乎总是可以写入,除非发送缓冲区已满,这意味着接收器的接收缓冲区已满,这意味着接收器比发送器慢。所以单独使用select()作为底层写定时器并不是一个好主意。