2013-04-27 83 views
0

我有一个单线程程序。它每五秒向四个目的地发送消息。我不想要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秒)。那么在这种情况下,我该如何实现目标?

  1. 如果所有套接字都准备好了,程序会继续。
  2. 如果任何一个套接字没有准备好,程序可以在那里阻塞2秒。
+0

您的编辑后,你的目标是不完整的。如果只有一些套接字准备就绪,程序应该做什么? – EJP 2013-04-28 00:25:38

+0

对不起,我没有说清楚我的观点。如果只有一些套接字准备就绪,程序应该等待2秒钟并丢弃那些未准备好的套接字。 – Edmund 2013-04-28 00:30:59

+0

那么这就是发生了什么,而选择()正在做你所需要的。那么你的问题是什么? – EJP 2013-04-28 00:46:43

回答

4

是的,select的设计假设你想在每个套接字准备就绪后立即为它服务。

如果我明白你想要做什么,那么完成它的最简单方法就是在fdset准备就绪时从fdset中移除每个套接字。如果集合中还有任何插座,请使用gettimeofday向下调整超时,然后再次呼叫select。当该组为空时,所有四个插座都可用,您可以继续。

0

我没有看到您陈述的目标和您陈述的问题之间的联系。你说select()会阻塞,直到至少有一个套接字准备就绪,但根据上面的目标#2,这正是你想要的。在所有四个套接字同时准备就绪之前,您所陈述的目标中没有关于阻塞的内容。

您还应该注意,除非发送缓冲区已满,这意味着接收方的接收缓冲区已满,这意味着接收方比发送方慢,所以套接字几乎总是可以写入。所以单独使用select()作为底层写定时器并不是一个好主意。

1

有三种基本方法:

如果你想保持严格便携式需要迭代:

  • 计算结束时间从您选择
  • 周期的当前时间和超时:
  • - 用这些fds创建fdset 尚未准备好
  • - 计算最大时间来等待
  • - select()
  • - remeber那些FDS是现在准备
  • - 如果休息结束时间达到或准备所有FDS
  • 结束周期
  • 现在你有准备FDS的知识和经过时间

如果你想留下来随身携带,但可使用线程

  • 开始n个线程
  • 每线程一个FD选择
  • 加入所有线程

如果没有需要移植:大多数操作系统有一个工厂这样的情况,例如在Windows/.NET具有了WaitAll(与异步发送和事件一起)