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() 一定成功 */
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 */
在 UNIX 系统上,我们通常会利用 select() 来做「polling」的动作,检查事件是否发生;但是在 MS Windows 3 的话, Winsock 系统内部可能不会呼叫到 Blocking Hook 函式来释放控制权)。UNIX 系统由於是「Time Sharing」的方式,所以并不会有类似的问题。(所谓 polling 的动作是指,您在程式中有一个回圈,而在回圈内一直呼叫像 select 这样的函式做检查的动作) select() 除了可以用来检查 socket 是否可读写外;对於 non-locking 的 socket 在呼叫 connect() 後,也可利用 select() 的 writefds 来检查连接是否已经成功了(当这个 non-blocking 的 socket 被设定在 writefds,且被 select 成功时);此外,我们亦可利用 readfds 来检查 TCP socket 连接的对方是否已经关闭了(当此 socket 被设定在 readfds,且被 select 成功,但呼叫 recv 去收资料却 return 0 时)。
(图 1.) select 函式的几种不同用途
UNIX 系统上因为没有提供 WSAAsyncSelect() 函式,所以我们要用 select() 函式来做 polling 的动作;但是 Winsock 系统上已经有了可以设定非同步事件的WSAAsyncSelect() 函式,为了让 MS Windows 「讯息驱动」(message driven)的环境更有效率,读者们应该尽量使用 WSAAsyncSelect(),而少用 select() 的方式;这也是当初为什麽要定义一个 WSAAsyncSelect() 函式的最大目的。
【变更 socket 的 options 的函式】
Winsock 1.1 也提供了一个变更 socket options 的 setsockopt() 函式;由於 options 的项目很多,笔者仅就数个较会用到的项目来解说,其馀的项目请读者们自行研究。
◎ setsockopt():设定 Socket 的 options。
格式: int PASCAL FAR setsockopt( SOCKET s, int level, int optname, const char FAR *optval, int optlen )
参数: s Socket 的识别码
level option 设定的 level (SOL_SOCKET 或 IPPROTO_TCP)
optname option 名称
optval option 的设定值
optlen