select函数的参数
( int nfds, fd_set readfds, fd_set writefds, fd_set exceptfds, const struct timeval timeout )
我记得是:第一个是个较为次要的值,设成0就行了。
后面的几个FD_SET类型的参数才是最重要的;
第一个FD_SET型的参数readfds是表示要被检查是否可读的 Sockets,把你想要接收数据的那个套接字放在这里;
第二个FD_SET参数ritefds是表示要被检查是否可写的 Sockets,将你要发送数据的套接字放在这里;
还有个FD_SET参数exceptfds是表示要被检查是否有错误的 Sockets
select() 函式的第五个参数timeout,是让我们用来设定 select 函数要等
待(block)多久。兹述说如下:
(1)如果 timeout 设为「NULL」,那么 select() 就会一直等到「至少」某
一个 socket 的事件成立了才会 return,这和其他的 blocking 函数一样。
select( ..., NULL ) /* blocking */
(2)如果 timeout 的值设为 {0, 0} (秒, 微秒),那么 select() 在检查后,不管有没有 socket 的事件成立,都会马上 return,而不会停留。
timeout.tv_sec = timeout.tv_usec = 0;
select( ..., &timeout ) /* non-blocking */
(3)如果 timout 设为 {m, n},那么就会等到至少某一个 socket 的事件发生,或是时间到了(m 秒 n 微秒),才会 return。
timeout.tv_sec = m;
timeout.tv_usec = n;
select( ..., &timeout ) /* wait m secconds n microseconds */
返回值: 成功 - 符合条件的 Sockets 总数 (若 Timeout 发生,则为 0)
失败 - SOCKET_ERROR (呼叫 WSAGetLastError() 可得知原因)
说明: 使用者可利用此函式来检查 Sockets 是否有资料可被读取,或是有空间可以写入,或是有错误发生。
关于对FD_SET类型的操作,有几个比较重要的宏:
FD_ZERO(*set) -- 将 set 的值清乾净
FD_SET(s, *set) -- 将 s 加到 set 中
FD_CLR(s, *set) -- 将 s 从 set 中删除
FD_ISSET(s, *set) -- 检查 s 是否存在於 set 中
参数 readfds、writefds、及 exceptfds 都是 「called by value-result」;而「called by value-result」的意思就是说,我们在将参数传给系统时,要先设启始值,并将这些参数的位址(address)告诉系统;而系统则会利用到这些值来做些运算或其他用途,最后并将结果再写回这些参数的位址中。
因此这些参数的值在传入前和函数返回后,可能会不同;所以每次调用select() 前,对这些参数一定要重新设定它们的值。
假设我们要检查 socket 1 和 2 目前是否可以用来传送资料,以及 socket 3 是否有资料可读;我们不打算检查 sockets 是否有错误发生,所以 exceptfds 设为NULL。步骤大致如下:
FD_ZERO( &writefds ); /* 清除 writefds */
FD_ZERO( &readfds ); /* 清除 readfds */
FD_SET( 1, &writefds ); /* 将 socket 1 加到 writefds */
FD_SET( 2, &writefds ); /* 将 socket 2 加到 writefds */
FD_SET( 3, &readfds ); /* 将 socket 3 加到 readfds */
select( ..., &readfds, &writefds, NULL, ...) /* 调用 select() 来检查事件 */
if (FD_ISSET( 1, &writefds )) /* 检查 socket 1 是否可写 */
send( 1, data ); /* 调用 send() 一定成功 */
if (FD_ISSET( 2, &writefds )) /* 检查 socket 2 是否可写 */
send( 2, data ); /* 调用 send() 一定成功 */
if (FD_ISSET( 3, &readfds )) /* 检查 socket 2 是否可读 */
recv( 3, data ); /* 调用 recv() 一定成功 */
不知道说得清不清楚?你明白了没有?
(jacky) |