I. Select
In Winsock # include <Winsock. h>
Prototype
IntSelect (
IntNFDs,
Fd_set *Readfds,
Fd_set *Writefds,
Fd_set *Exceptfds,
Const struct timeval *Timeout
);
NFDs: this parameter is ignored and only works for compatibility.
Readfds: (optional) pointer pointing to a set of interfaces waiting for readability check.
Writefds: (optional) pointer pointing to a set of interfaces waiting for writable checks.
Required TFDs: (optional) pointer pointing to a set of interfaces waiting for error checks.
Timeout: Select () can wait for a maximum of time, and is null for blocking operations.
Note:
This function is used to determine the status of one or more interfaces. For each set of interfaces, the caller can query its readability, writability, and error status information.
The fd_set structure is used to represent a set of interfaces waiting for inspection. When a call returns, this structure contains a subset of the Set interface groups that meet certain conditions, and select () returns the number of sets of interfaces that meet the conditions.
A set of macros can be used for fd_set operations. These macros are compatible with the Berkeley UNIX software, but their internal expressions are completely different.
Parameters:
Readfds: identifies the set of interfaces waiting for readability checks. If the set of interfaces is in the listen () Listening state, if a connection request arrives, the set of interfaces will be identified as readable, so that an accept () call can be completed without blocking.
For other interfaces, readability means queuing data is available for reading.
Or for an interface of the sock_stream type, the Recv () or recvfrom () operations can be completed without blocking because the Virtual Interface of this interface has been disabled.
If the virtual circuit is "elegantly" aborted, The Recv () will return immediately if it does not read data. If the virtual circuit is forcibly reset, The Recv () will return immediately if the wsaeconnreset error is returned. If the so_oobinline option is set, it checks whether out-of-band data exists (see setsockopt ()).
Writefds: Specifies the set of interfaces waiting for writable checks. If a set of interfaces is being connected (non-blocking), writability means that the connection is established smoothly. If the set of APIS is not in the connect () call, writability means that the send () and sendto () calls will be completed without blocking. [However, it does not indicate how long this guarantee will take effect, especially in a multi-threaded Environment 〕.
Required TFDs: identifies an interface that waits for the existence of out-of-band data or indicates an error condition check. Note that if the so_oobinline option is set to false, you can only use this method to check whether out-of-band data exists. For the so_stream interface, the connection suspension and keepalive errors caused by the remote end will be treated as errors. If the set of interfaces is connecting to connect () (non-blocking), the connection attempt failure will be manifested in the limit TFDs parameter.
If you are not interested in any group of classes in readfds, writefds, or TFDs, you can leave it null.
In the Winsock. h header file, four macros are defined to operate the description word set. The fd_setsize variable is used to determine the maximum number of descriptive words in a set (the default value of fd_setsize is 64. You can use # define fd_setsize to change this value before including Winsock. h ). For internal representation, fd_set is represented as a queue with a set of interfaces, and the subsequent element of the last valid element is inval_socket. MACRO:
Fd_clr (S, * Set): deletes the description word s from the set.
Fd_isset (S, * Set): If S is a member of the set, it is non-zero; otherwise, it is zero.
Fd_set (S, * Set): add the description word s to the set.
Fd_zero (* Set): Initialize the set to null.
Timeout: controls the time when select () is completed. If the timeout parameter is a null pointer, select () will be blocked until a descriptive word meets the conditions. Otherwise, timeout points to a timeval structure, which specifies how long the select () call will wait before returning. If timeval is {0, 0}, select () returns immediately, which can be used to query the status of the selected interface. If it is in this state, the Select () call can be considered non-blocking, and all assumptions applicable to non-blocking calls apply to it. For example, the blocking hook function should not be called, and the implementation of Windows interfaces should not be yield.
After the timeout value is set, if the SELECT statement does not have a file descriptor to monitor the availability, it will wait for the timeout time. When the time reaches, the SELECT statement returns 0.
If a file descriptor is available before the timeout times out, the available quantity is returned. At this time, the timeout still counts, therefore, if you want to time out each time for a certain period of time, you must reload the value of timeout once after slelect returns a value greater than 0. To ensure that the timeout time does not change.
If both TV _sec and TV _usec are 0, the timeout value is 0, and the SELECT statement returns immediately.
If timeout is null, the timeout is not enabled and will be blocked in the monitored file descriptor.
Return Value:
The Select () call returns the total number of descriptive words that are in the ready state and already included in the fd_set structure. If the call times out, 0 is returned. Otherwise, the socket_error is returned. The application can use wsagetlasterror () obtain the error code.
Error code:
Wsanotinitialised: before using this API, you must successfully call wsastartup ().
Wsaenetdown: A Windows interface is used to detect the failure of the network subsystem.
Wsaeinval: the timeout value is invalid.
Wsaeintr: cancels a (blocking) call through a wsacancelblockingcall.
Wsaeinss SS: A blocked Windows interface call is running.
Wsaenotsock: A descriptive word set contains non-interface elements.
The Select () function is mainly based on the fd_set type. Fd_set is a collection of file descriptors (FD). It represents an FD with one digit (which will be described in detail below ), for the fd_set type, use the following four macros:
Fd_set set;
Fd_zero (& set );
Fd_set (FD, & set );
Fd_clr (FD, & set );
Fd_isset (FD, & set );
In the past, an fd_set usually only contains <32 FD (File description), because fd_set actually only uses a 32-bit vector to represent FD. Now, in Unix systems, the header file <sys/select. h> defines the constant fd_setsize, which is the number of descriptive words of the Data Type fd_set. The value is usually 1024, which indicates the FD of <1024. Based on the bit vector Implementation of fd_set, we can re-understand the four macros that operate fd_set:
Fd_set set;
Fd_zero (& set );
Fd_set (0, & set );
Fd_clr (4, & set );
Fd_isset (5, & set );
―――――――――――――――――――――――――――――――――――――――
Note that the maximum value of FD must be <fd_setsize.
―――――――――――――――――――――――――――――――――――――――
The select function interface is relatively simple:
Int select (INT NFDs, fd_set * readset, fd_set * writeset,
Fd_set * effectset, struct Tim * timeout );
Function:
Test the specified FD readable? Writable? Are there any exception conditions to be processed?
Parameters:
NFDs: number of file description words to be checked (that is, the number of characters in fd_set). The value should be greater than the maximum FD contained in the three fd_set groups.
A larger value is generally set to the maximum FD value included in the three fd_set groups plus 1 (for example, the maximum value included in readset, writeset, and effectset ).
If FD is 5, NFDs = 6 because FD starts from 0 ). Set this value to improve efficiency so that the function does not have to check the fd_set
There are 1024 bits.
Readset: A group of file descriptions used to check readability.
Writeset: A group of file descriptions used to check the writability.
Effectset: Specifies the file description used to check for exceptions. (Note: errors are not included in the exception conditions)
Timeout: There are three possibilities:
1: timeout = NULL (blocking: it is returned only when an FD bit is set to 1)
2: The structure pointed to by timeout is set to a non-zero time (wait for a fixed time: There is a FD bit set to 1 or the time is exhausted, the function
Returns)
3. The structure pointed to by timeout. The time is set to 0 (non-blocking: The function returns immediately after checking each FD)
Return Value:
Returns the total number of FD instances whose corresponding bits are still 1.
Remarks:
All three fd_sets set 0 for some FD locations. Only the readable, writable, and exceptional FD bits to be processed are still 1.
The process of using the select function is generally:
First, call the macro fd_zero to clear the specified fd_set, then call the macro fd_set to add the FD to be tested to the fd_set, and then call the function.
Select tests all FD in fd_set, and then uses the macro fd_isset to check whether the corresponding bit of a FD is still 1 after the select function is called.
The following is an example of testing the readability of descriptive words in a single file:
Int isready (int fd)
{
Int RC;
Fd_set FDS;
Struct Tim TV;
Fd_zero (& FDs );
Fd_set (FD, & FDs );
TV. TV _sec = TV. TV _usec = 0;
Rc = select (FD + 1, & FDS, null, null, & TV );
If (RC <0) // Error
Return-1;
Return fd_isset (FD, & FDs )? 1: 0;
}
The following is a complex application:
// This Code specifies the readability and writability of the socket description, because the socket uses FD
Uint32 socketwait (tsocket * s, bool Rd, bool WR, uint32 timems)
{
Fd_set rfds, wfds;
# Ifdef _ Win32
Tim TV;
# Else
Struct Tim TV;
# Endif
Fd_zero (& rfds );
Fd_zero (& wfds );
If (RD) // true
Fd_set (* s, & rfds); // Add the description to be tested
If (WR) // false
Fd_set (* s, & wfds );
TV. TV _sec = timems/1000; // second
TV. TV _usec = timems00; // MS
For (;) // If errno = eintr, repeatedly test the readability of the buffer.
Switch (select (* s) + 1, & rfds, & wfds, null,
(Timems = time_infinite? Null: & TV) // test whether the interface receives data in the buffer zone within the specified time.
{// 0 -- timeout,-1 -- Error
Case 0:
Return 0;
Case (-1 ):
If (socketerror () = eintr)
Break;
Return 0; // error, but not eintr
Default:
If (fd_isset (* s, & rfds) // If S is a member of FDS, non-0 is returned; otherwise, 0 is returned.
Return 1;
If (fd_isset (* s, & wfds ))
Return 2;
Return 0;
};
}
Q &:
Four macros closely integrated with the select model:
Fd_clr (int fd, fd_set * Set );
Fd_isset (int fd, fd_set * Set );
Fd_set (int fd, fd_set * Set );
Fd_zero (fd_set * Set );
The key to understanding the select model is to understand fd_set. For convenience, the length of fd_set is 1 byte. Each bit in fd_set can correspond to a file descriptor FD. The fd_set with a length of 1 byte can correspond to a maximum of 8 FD.
(1) execute fd_set set; fd_zero (& set); then set uses bits to indicate that it is 00.
(2) If FD = 5, execute fd_set (FD, & set); then set to 0001,0000 (5th position is 1)
(3) If FD = 2 or FD = 1 is added, Set Becomes 0001,0011.
(4) execute select (6, & set, 0, 0) to block the wait
(5) If both FD = 1 and FD = 2 have readable events, select returns, and set changes.Note:FD = 5 with no event occurred is cleared.
Based on the above discussion, we can easily draw the features of the select model:
(1) the number of monitored file descriptors depends on the value of sizeof (fd_set. Sizeof (fd_set) = 512 on my server. Each bit represents a file descriptor. The maximum file descriptor supported on my server is 512x8 = 4096. For details about how to adjust the fd_set size, refer to limit.
(2) When FD is added to the select monitoring set, another data structure array must be used to store FD in the select monitoring set. The first is used to return the result after the SELECT statement, array is used as the source data and fd_set for fd_isset judgment. SecondAfter the SELECT statement is returned, the previously added but no event occurs in FD will be cleared, and the FD will be re-obtained from array one by one before each select operation.(Fd_zero first), scans the array and obtains the FD maximum value maxfd. This is the first parameter used for select.
(3) it can be seen that the select model must loop array (add FD, take maxfd) before Select, And Then loop array (fd_isset to determine whether an event has occurred) After Select returns ).
In addition, if the wait time is set in the Select call, do you need to assign a new value to this time during each call? It is like processing fd_set.
For example:
Fd_set readfd;
Struct timval TV;
While (1 ){
Fd_zero (& readfd );
Fd_set (FD, & readfd );
TV. TV _sec = 2;
TV. TV _usec = 0;
Select (maxfd + 1, & readfd, null, null, & TV );
......;
}
As shown in the above Code, every call to fd_set needs to be reset. is the same for TV? Can you assign a value to TV outside while?
The answer is no. If the time Initialization is placed outside, the time is initialized to 2 seconds. If an event is sent after 1 second, then select will return and change the TV time to the remaining time of the last blocking, that is, 1 second, and then monitor the socket. This is becauseIn the implementation of select () in Linux, the TV parameter is changed to the remaining time.. Therefore, for the last parameter in the select function, you need to set it in the loop, and set it again for each loop. If it is located outside the loop, after the loop is executed, the TV value will be changed for each loop select, and the TV value will be smaller and smaller, in the end, the Select function will be generated. This TV time cannot receive the valid time, and-1 will be returned, resulting in an error.
Socket readable:
1. The receiving buffer zone has data that must be readable.
2. The other party closes the socket normally and is also readable.
3. For listening socket, there are new links arriving and readable
Socket basic functions (2)