Сетевое программирование в .NET. Расшифровка IP-адреса (IP address specification). Обеспечение надежности доставки пакетов, страница 31

The numfd parameter specifies the highest value of the file descriptors (sockets) that the select function is monitoring, plus one. The select() function can thus know how high to iterate when testing the socket sets. The readfds, writefds, and exceptfds parameters specify the following lists (or sets) of sockets to be monitored by select() for the specific data function: readfds Sockets that are checked if data is available to read writefds Sockets that are checked if ready to write exceptfds Sockets that are checked for exceptions The timeout parameter defines a timeval structure to set how long the select() function should wait for any of the sockets to have an event. The tricky part of socket multiplexing is assigning sockets to the readfds, writefds, and exceptfds parameters. Indeed, there is another whole set of functions that do that, as listed in Table 3.3.

Function Description

FD_ZERO(set) Zeros out a multiplex set set

FD_SET(socket, set) Adds socket to the multiplex set set

FD_CLR(socket, set) Removes socket from the multiplex set set

FD_ISSET(socket, set) Tests to see if socket is contained in the multiplex set set

The helper functions must be used to set the individual socket sets for each select() call. A select() call cancels out any previous select() calls. Thus you must add or remove any new sockets to or from the existing set before the next call to the select() function. Here is an example of using the select() method:

sock1 = socket(PF_INET, SOCKET_STREAM, 0);

sock2 = socket(PF_INET, SOCKET_STREAM, 0);

connect(sock1, addr, addrlen);

connect(sock2, addr2, addr2len);


FD_SET(sock1, &sockset);

FD_SET(sock2, &sockset);

if (sock1 > sock2)

maxfd = sock1 + 1;


maxfd = sock2 + 1;

timeout.tv_sec = 30;

timeout.tv_usec = 0;

select(maxfd, &sockset, NULL, NULL, &timeout);

if (FD_ISSET(sock1, &sockset))

recv(sock1, buffer1, sizeof(buffer1), 0);

if (FD_ISSET(sock2, &sockset))

recv(sock2, buffer2, sizeof(buffer2), 0);

This example shows how the select() function can be used to monitor two separate socket connections. Once select() is called with the appropriate socket sets, you can use the FD_ISSET helper function at any time in the program to test if data is available for an individual socket. After select()finishes (either by receiving an event or from the timeout) the socketset value contains only those sockets that have had an event trigger. By using FD_ISSET, you can determine whether either socket is receiving data. If either socket does not have any data, it is not part of the set and does not block the rest of the program.

Winsock Non-blocking Socket Functions

Another similarity to the Unix network environment is that Winsock supplies ways to prevent network I/O functions from blocking the program execution. Winsock supports the standard Unix methods of setting a socket to non-blocking mode using the ioctlsocket() function (similar to the Unix fcntl() function) and the select() function to multiplex multiple sockets. The ioctlsocket() format is as follows:

ioctlsocket(SOCKET s, long cmd, u_long FAR* argp)

The socket to be modified is s, the cmd parameter specifies the operation to make on the socket, and the argp parameter specifies the command parameter. In addition to these standard socket functions, the Winsock interface offers additional methods of allowing non-blocking network I/O.


One of the features that differentiates Windows from standard Unix programs is the concept of events. Unlike common structured programs that have a set way of executing, Windows programs are usually event driven. Methods are executed in the program in response to events occurring while the program is running—buttons are clicked, menu items are selected, and so on. The standard technique of waiting around for data to occur on network sockets does not fit well in the Windows event model. Event-driven access to network sockets is the answer.