The Select function is used in non-blocking, when a socket or a set of sockets is signaled, the system provides a select function to implement the multiplexed input/output model, the prototype:
#include <sys/time.h>
#include <unistd.h>
int select (int maxfd,fd_set *rdset,fd_set *wrset,fd_set *exset,struct timeval *timeout);
The parameter maxfd is the largest file descriptor value that needs to be monitored +1;rdset,wrset,exset corresponds to a collection of readable file descriptors that need to be instrumented, a collection of writable file descriptors, and a collection of exception file descriptors. The struct TIMEVAL structure is used to describe a length of time, and the return value is 0 if the descriptor that needs to be monitored does not have an event occurred during this time.
Fd_set (which is important so first) is a set of file description words (FD), which is represented by a single FD (described below), for the Fd_set type by the following four macros:
Fd_zero (Fd_set *fdset); The specified file description is Fu Giuqing empty, and the file descriptor collection must be initialized before it is set, and if not emptied, the result is not known because it is usually not emptied after the system allocates memory space.
Fd_set (int fd, Fd_set *fdset), used to add a new file descriptor to the file descriptor collection.
FD_CLR (int fd, fd_set *fdset); Used to delete a file descriptor in the file descriptor collection.
Fd_isset (int fd, Fd_set *fdset), which is used to test whether the specified file descriptor is in the collection.
In the past, a fd_set usually can only contain <32 fd (file descriptor), because Fd_set actually only uses a 32-bit vector to represent FD; UNIX systems now typically define constants in header file <sys/select.h> fd_ SETSIZE, which is the number of descriptive words for the data type Fd_set, is usually 1024, which can represent the FD of <1024. Based on the fd_set bit vector implementation, we can re-understand the operation of the Fd_set four macros:
Fd_set set;
Fd_zero (&set);
Fd_set (0, &set);
FD_CLR (4, &set);
Fd_isset (5, &set);
―――――――――――――――――――――――――――――――――――――――
Note the maximum value of FD must be <fd_setsize.
―――――――――――――――――――――――――――――――――――――――
The interface of the Select function is relatively straightforward:
int select (int Nfds, fd_set *readset, fd_set *writeset,fd_set* exceptset, struct Tim *timeout);
Function:
Test the specified FD-readable? Can write? Have abnormal conditions pending?
Parameters:
-- nfds
the number of file descriptors that need to be checked (that is, the first fd_set to check), The value should be larger than the maximum FD value contained in the three sets of fd_set, typically set to the maximum FD values in the three group Fd_set plus 1 (if the largest FD in Readset,writeset,exceptset is 5, then nfds=6, since FD is starting from 0). Setting this value is for increased efficiency so that the function does not have to check all 1024 bits of fd_set.
-- readset
A set of file descriptors used to check readability.
-- writeset
A set of file descriptors that are used to check for the writable character.
-- exceptset
A file descriptor that is used to check for abnormal conditions. (Note: The error is not included in the exception condition)
-- timeout
is used to describe a length of time, and the return value is 0 if the descriptor that needs to be monitored does not have an event occurred during this time.
There are three possibilities:
1.timeout= NULL (blocked: Select will be blocked until an event occurs on a file descriptor)
2. The structure pointed to by timeout is set to a nonzero time (wait for a fixed time: if there are events or time runs out in the specified time period, the function returns)
3. Timeout points to a structure with a time set of 0 (non-blocking: detects only the state of the descriptor collection and then returns immediately without waiting for an external event to occur)
return value:
Returns the total number of FD that corresponds to a bit that is still 1.
Remarks:
All three groups of Fd_set will have some FD positions of 0, only those that are readable, writable, and have abnormal conditions pending the FD bit remains 1.
For example, recv (), when there is no data to call it, your thread will be blocked, and if the data is not coming, your thread is going to block for a long time. This is obviously not good.
So use Select to see if the nested word is readable (that is, if there is data to read)
The steps are as follows--
socket s;
.....
Fd_set set;
while (1)
{
Fd_zero (&set);//Empty your set of knots
Fd_set (S, &set);//Add the section Word you are interested in to the collection, here is a section of the read data s
Select (0,&set,null,null,null);//Check if the socket is readable,
In many cases, there is data (note, just a lot of things).
Here Select whether error did not write
if (Fd_isset (S, &set)//Check if s is inside this set,
{//select will update this collection to remove the unreadable nested word
Keep only the qualifying section words in this set
Recv (s,...);
}
Do something here
}
The key to understanding the Select model is to understand fd_set, for illustrative convenience, take fd_set length of 1 bytes, each bit in fd_set can correspond to a file descriptor FD. The 1-byte-long fd_set can correspond to 8 fd maximum.
(1) Execute fd_set set; Fd_zero (&set); The set is represented by a bit 0000,0000.
(2) If fd=5, execute Fd_set (fd,&set), then SET to 0001,0000 (5th position 1)
(3) If you add fd=2,fd=1 again, set becomes 0001,0011
(4) Execute select (6,&set,0,0,0) blocking wait
(5) If a readable event occurs on the fd=1,fd=2, select returns, at which point the set becomes 0000,0011. Note: No event occurs when the fd=5 is emptied.
Based on the above discussion, it is easy to derive the features of the Select model:
(1) The number of file descriptors that can be monitored depends on the value of sizeof (Fd_set). My side on the server sizeof (fd_set) = 512, each bit represents a file descriptor, then the maximum file descriptor supported on my server is 512*8=4096. It is said to be adjustable, although it can be adjusted, the upper limit is dependent on the value of the variable when compiling the kernel. I am not very interested in adjusting the size of the fd_set, the reference to model 2 (1) in http://www.cppblog.com/CppExplore/archive/2008/03/21/45061.html can effectively break the upper limit of the file descriptor that can be monitored by SELECT.
(2) When the FD is added to the Select Monitor set, an array of data structures is used to save the FD in the Select monitoring set, and the array is used as the source data and fd_set for Fd_isset judgment after the select return. Second, the select return will be previously joined but no event of the FD emptied, then each start select before starting to re-get FD from the array to join (Fd_zero first), scan the array at the same time to obtain the FD maximum MAXFD, for the first parameter of select.
(3) The Select model must loop array (plus FD, fetch MAXFD) in front of SELECT, and select Returns a loop array (Fd_isset determines if there is time).
Here is a pseudo-code to illustrate the server model of the basic Select model:
Array[slect_len];
nsock=0;
ARRAY[NSOCK++]=LISTEN_FD (previously listen port is bound and listen)
MAXFD=LISTEN_FD;
while{
Fd_zero (&set);
foreach (fd in array)
{
FD is greater than maxfd, then MAXFD=FD
Fd_set (Fd,&set)
}
Res=select (maxfd+1,&set,0,0,0);
if (Fd_isset (Listen_fd,&set))
{
Newfd=accept (LISTEN_FD);
ARRAY[NSOCK++]=NEWFD;
if (--res=0) continue
}
foreach Subscript 1 start (fd in array)
{
if (Fd_isset (Fd,&set))
Perform read and other related operations
If it is wrong or closed, delete the FD, swap the corresponding position in the array with the last element, and Nsock minus one.
if (--res=0) continue
}
}
The process of using the Select function is generally:
Call the macro Fd_zero the specified fd_set, then call the macro Fd_set will need to test the FD join Fd_set, then call the function Select Test Fd_set all FD, and finally use the macro fd_isset to check that an FD after the function select Call, Whether the corresponding bit is still 1.
Here is an example that tests the readability of a single file description word:
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;
}
Here's a more complex application:
This code specifies the readable legibility of the description of the test socket, because the socket uses the 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 a descriptive word to test
if (WR)//false
Fd_set (*s,&wfds);
tv.tv_sec=timems/1000; Second
tv.tv_usec=timems%1000; Ms
for (;;)//If errno==eintr, test the readability of the buffer repeatedly
Switch (select (*s) +1,&rfds,&wfds,null,
(Timems==time_infinite?) NULL:&TV))//test whether there is data readable in the socket receive buffer within the specified time
{//0--timed out, -1--error
Case 0:
return 0;
Case (-1):
if (SocketError () ==eintr)
Break
return 0; Wrong, but not eintr.
Default
if (Fd_isset (*S,&RFDS))//If S is a member of FDS returns non 0, otherwise returns 0
return 1;
if (Fd_isset (*s,&wfds))
return 2;
return 0;
};
}
Select () function and Fd_zero, Fd_set, FD_CLR, Fd_isset (GO)