Copyright Disclaimer: During reprinting, please use hyperlinks to indicate the original source and author information of the article and this statement
Http://eastsun.blogbus.com/logs/7873846.html
Select is still important in socket programming, but it is not very popular for beginners of socket programming, they are just used to writing blocking programs such as connect, accept, Recv, or recvfrom (the so-called blocking method block, as the name suggests, means that the process or thread must wait for an event to occur when executing these functions, if the event does not occur, the process or thread will be blocked and the function cannot return immediately ). However, using select can achieve non-blocking (the so-called non-block method means that the process or thread does not have to wait for the event to execute this function. Once executed, it will definitely return, different return values are used to reflect the execution of the function. If the event occurs in the same way as the blocking method, if the event does not occur, a code is returned to inform the event that the event has not occurred, while the process or thread continues to execute, so it is more efficient). It can monitor changes in file descriptors that we need to monitor-read/write or exceptions. The following is a detailed introduction!
Select Function Format (I am talking about Berkeley socket programming in UNIX, which is different from that in windows. I will explain it later ):
Int select (INT maxfdp, fd_set * readfds, fd_set * writefds, fd_set * errorfds, struct timeval * timeout );
Two struct types are described first:
First, struct fd_set can be understood as a collection in which the file descriptor (file descriptor) is stored, that is, the file handle. This can be what we call a common object, of course, any device, pipeline, and FIFO in UNIX are all in the file format, so there is no doubt that a socket is a file, and a socket handle is a file descriptor. The fd_set set can be operated manually by some macros, such as clearing the set fd_zero (fd_set *) and adding a given file descriptor to the set fd_set (INT, fd_set *), delete a given file descriptor from the collection fd_clr (INT, fd_set *) and check whether the specified file descriptor in the collection can read and write fd_isset (INT, fd_set *). For example.
Second, struct timeval is a common structure used to represent the time value. It has two members: one is the number of seconds and the other is the number of milliseconds.
Specific interpretation of select parameters:
Int maxfdp is an integer that indicates the range of all file descriptors in the collection. That is, the maximum value of all file descriptors is 1. It cannot be wrong! In Windows, the value of this parameter does not matter. You can set it incorrectly.
Fd_set * readfds is a pointer to the fd_set structure. This collection should contain file descriptors. We want to monitor the read changes of these file descriptors, that is, we are concerned about whether data can be read from these files. If a file in this collection is readable, select returns a value greater than 0, indicating that the file is readable, if there is no readable file, the timeout parameter is used to determine whether to time out. If the time exceeds the timeout time, select returns 0. If an error occurs, a negative value is returned. You can pass in a null value, indicating that you do not care about any file read changes.
Fd_set * writefds is a pointer to the fd_set structure. This collection should contain file descriptors. We want to monitor the write changes of these file descriptors, that is, we are concerned about whether data can be written to these files. If there is a file in this collection that can be written, select will return a value greater than 0, indicating that a file is writable, if no writable file exists, the timeout parameter is used to determine whether to time out. If the time exceeds the timeout time, select returns 0. If an error occurs, a negative value is returned. You can pass in a null value, indicating that you do not care about any file write changes.
Fd_set * errorfds indicates the intention of the two parameters above, which is used to monitor file error exceptions.
Struct timeval * timeout is the select timeout time. This parameter is crucial. It can make the SELECT statement in three States. First, if null is input as an input parameter, that is, the time structure is not input, that is, the SELECT statement is placed in the blocking state. It must wait until a file descriptor in the collection of monitored file descriptors changes. Second, if the time value is set to 0 s and 0 ms, it becomes a pure non-blocking function. no matter whether the file descriptor has changed or not, it immediately returns to continue execution. If the file does not change, 0 is returned, and a positive value is returned. Third, the value of timeout is greater than 0, this is the waiting timeout time, that is, the SELECT statement is blocked within the timeout time, and an event will be returned within the time-out time. Otherwise, no matter how long it will be returned, the return value is the same as the above.
Return Value:
Negative value: Select error positive value: some files can be read or written, or errors 0: wait for timeout, there is no readable or wrong file
With select, you can write a decent network program! A simple example is to accept data from the network and write it into a file.
Example:
Main ()
{
Int sock;
File * FP;
Struct fd_set FDS;
Struct timeval timeout = {3, 0}; // select wait 3 seconds, 3 seconds round-robin, set to 0 if it is not blocked
Char buffer [256] = {0}; // receiving buffer of 256 bytes
/* Assume that a UDP connection has been established, and the specific process is not written or simple. Of course, the same applies to TCP. The host IP address and port are already specified, and the file to be written has already been opened.
Sock = socket (...);
BIND (...);
Fp = fopen (...);*/
While (1)
{
Fd_zero (& FDs); // clear the set for each loop. Otherwise, the descriptor changes cannot be detected.
Fd_set (sock, & FDs); // Add Descriptor
Fd_set (FP, & FDs); // same as above
Maxfdp = sock> FP? Sock + 1: FP + 1; // Add 1 to the maximum value of the descriptor
Switch (select (maxfdp, & FDS, & FDS, null, & timeout) // select
{
Case-1: exit (-1); break; // select error, exit the program
Case 0: break; // Round Robin again
Default:
If (fd_isset (sock, & FDs) // test whether sock is readable, that is, whether there is data on the network.
{
Recvfrom (sock, buffer, 256,...); // accept Network Data
If (fd_isset (FP, & FDs) // test whether the file can be written
Fwrite (FP, buffer...); // write a file
Buffer clearing;
} // End if break;
} // End Switch
} // End while
} // End main