Select in the socket programming is still more important, but for beginners socket people are not too fond of using select Write program, they just used to write such as Connect, accept, Blocking programs such as recv or recvfrom (the so-called block mode block, as the name implies, is that a process or thread must wait for an event to occur when it executes to these functions, and if the event does not occur, the process or thread is blocked and the function cannot be returned immediately). However, a non-blocking (so-called nonblocking mode non-block is done using SELECT, that is, the process or thread does not have to wait for the event to occur, and once the execution is returned, the return value is different to reflect the execution of the function, if the event occurs in the same way as the block. If the event does not occur, return a code to tell the event not to occur, and the process or thread continues to execute, so it is more efficient to work on the program, which can monitor the change of the file descriptor we need to monitor-read-write or exception. Here is a detailed introduction!
The function format of select (I'm talking about the Berkeley socket programming under UNIX systems, and the difference under Windows, for a moment):
int select (int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
The two structures are described first:
First, the struct fd_set can be understood as a collection, this collection is stored in the file descriptor (descriptor), that is, the file handle, this can be what we call the ordinary meaning of the file, of course, UNIX under any Device, pipeline, FIFO, etc. are file forms, All included, so there is no doubt that a socket is a file, and the socket handle is a file descriptor. The Fd_set collection can be manipulated by some macros, such as emptying the set Fd_zero (Fd_set *), adding a given file descriptor to the collection fd_set (int, fd_set *), removing a given file descriptor from the collection fd_clr (int, fd_set*), checks whether the specified file descriptor in the collection can read and write Fd_isset (int, fd_set*). A moment to illustrate.
Second, struct timeval is a common structure that is used to represent time values, have two members, one is seconds, the other is the number of milliseconds.
Explain the parameters of select in detail:
int MAXFDP is an integer value that refers to the range of all file descriptors in the collection, that is, the maximum value of all file descriptors plus 1, not wrong! The value of this parameter in Windows does not matter and can be set incorrectly.
Fd_set *readfds is a pointer to the FD_SET structure, which should include the file descriptor, we want to monitor the read changes of these file descriptors, that is, we care whether the data can be read from these files, if there is a file in this collection is readable, Select returns a value greater than 0, indicating that the file is readable, and if there is no readable file, the timeout parameter is used to determine whether to time out, and if timeout is exceeded, select returns 0 if an error returns a negative value. You can pass in a null value to indicate that you do not care about any file read changes.
Fd_set *writefds is a pointer to the FD_SET structure, which should include the file descriptor, we want to monitor the write changes of these file descriptors, that is, we care about whether the data can be written to these files, if there is a file in this collection can be written, Select returns a value greater than 0, indicating that a file is writable, and if there is no writable file, the timeout parameter is used to determine whether to time out, and if timeout is exceeded, select returns 0 if an error returns a negative value. You can pass in a null value to indicate that you do not care about any file write changes.
Fd_set *errorfds with the above two parameters to monitor file error exceptions.
The struct timeval* timeout is the time-out for Select, which is critical, which allows the select to be in three states, first, if NULL is passed in as a parameter, that is, the time structure is not passed in, the select is put in a blocking state, Be sure to wait until one of the file descriptors in the monitor file descriptor collection changes; second, if the time value is set to 0 seconds 0 milliseconds, it becomes a purely non-blocking function, regardless of whether the file descriptor is changed, immediately return to continue execution, the file has no change return 0, there is a change to return a positive value; Timeout value is greater than 0, this is the waiting time-out period, that is, select in timeout time block, the timeout period has the arrival of the event to return, otherwise after the timeout, anyway must return, the return value with the above.
return value:
Negative value: Select Error positive value: Some files can be read or write or error 0: Wait timeout, no writable or incorrect files
After you have a select, you can write a decent network program! As a simple example, the acceptance of data from the network is written to a file.
Example:
Main ()
{
int sock;
FILE *FP;
struct Fd_set FDS;
struct Timeval timeout={3,0}; Select Waits 3 seconds, 3 seconds to poll, 0 for non-blocking
Char buffer[256]={0}; 256-byte Receive buffer
/* Assuming that the UDP connection has been established, the specific process is not written, simple, of course, TCP is also the same, the host IP and port are given, the file to be written has been opened
Sock=socket (...);
Bind (...);
Fp=fopen (...); */
while (1)
{
Fd_zero (&fds); The collection must be emptied for Each loop, or descriptor changes cannot be detected
Fd_set (Sock,&fds); Add a descriptor
Fd_set (Fp,&fds); Ditto
maxfdp=sock>fp?sock+1:fp+1; Descriptor Maximum Value plus 1
Switch (select (maxfdp,&fds,&fds,null,&timeout))//select use
{
Case-1: Exit ( -1); break; Select error, exiting the program
Case 0:break; Poll again
Default
if (Fd_isset (SOCK,&FDS))//test sock is readable, i.e. whether there is data on the network
{
Recvfrom (sock,buffer,256,.....); /Accept Network data
if (Fd_isset (FP,&FDS))//test file is writable
Fwrite (Fp,buffer ...); /write File
Buffer empty;
}//End If break;
}//End Switch
}//end while
}//end Main
Reference: http://cuijinbird.blogchina.com/cuijinbird/1921117.html
Part 2:
The mechanism of Select () provides a FD_SET data structure, which is actually a long type of array,
Each array element can be associated with an open file handle, whether it is a socket handle or another
A file or named pipe or device handle) to establish a connection, the work of establishing a connection is done by the programmer,
When select () is called, the kernel modifies the contents of the Fd_set based on the IO state, thereby notifying the
Okay, the process of select () which socket or file is readable, the following specific explanation:
#include <sys/types.h>
#include <sys/times.h>
#include <sys/select.h>
int Select (Nfds, Readfds, Writefds, Exceptfds, timeout)
int Nfds;
Fd_set *readfds, *writefds, *exceptfds;
struct Timeval *timeout;
Ndfs:select the number of file handles monitored, depending on the number of files opened in the process, is generally set to monitor each file
The maximum file number in the add one.
A collection of readable file handles that are monitored by the readfds:select.
A collection of writable file handles that are monitored by the writefds:select.
Exceptfds:select a collection of exception file handles that are monitored.
Timeout: The time-out period for this select (). (See/usr/sys/select.h,
Accurate up to one out of 10,000 seconds! )
When the Readfds or Writefds image file is readable or writable or timed out, this select ()
The return is ended. Programmers take advantage of a set of system-provided macros at the end of select () to
Which file is readable or writable. The Readfds is especially useful for socket programming.
A few related macros are explained below:
Fd_zero (Fd_set *fdset): empties Fdset contact with all file handles.
Fd_set (int fd, Fd_set *fdset): Establishes a file handle for the relationship between FD and Fdset.
FD_CLR (int fd, Fd_set *fdset): Clears the file handle to the relationship between FD and Fdset.
Fd_isset (int fd, Fdset *fdset): Checks if the file handle of the Fdset contact is FD
Can read and write, >0 means to read and write.
(See/usr/include/sys/types.h for definitions of fd_set and related macros)
In this way, your socket needs to be read only when there is something to read, roughly as follows:
...
int sockfd;
Fd_set FdR;
struct Timeval timeout = ...;
...
for (;;) {
Fd_zero (&FDR);
Fd_set (SOCKFD, &FDR);
Switch (SELECT (SOCKFD + 1, &FDR, NULL, &timeout)) {
Case-1:
Error handled by U;
Case 0:
Timeout hanled by U;
Default
if (Fd_isset (SOCKFD)) {
Now u read or recv something;
/* If SOCKFD is father and
Server socket, u can now
Accept () */
}
}
}
So a fd_isset (SOCKFD) is quite informed of the sockfd readable.
As for struct timeval in this function, please man select. Different Timeval settings
Enable select () to end, no timeout blocking, and poll three features. Because
Timeval is accurate to one out of 10,000 seconds, so the SetTimer () of Windows doesn't count
What the. You can make a super clock with select ().
The implementation of Fd_accept? Still as above, because the client socket requests the connection, it sends
Connection request message, at this time select () Of course will end, Fd_isset (SOCKFD) of course big
In 0, because there is a message to read it! As for the application of this aspect, the main reason is that the service party's parent
Socket, if you do not like the active accept (), you can instead of the above mechanism to accept ().
As for the implementation of the Fd_close and processing, a lot of CPU processing time, not to be continued.
--
Discusses the issue of using Select () to detect each other's socket closure:
Still the local socket has something to read, because when the other socket is closed, a close connection will be sent
The notification message is immediately detected by select (). Connection to TCP (three-time handshake) and off
(Two-time handshake) mechanism, please refer to the book on TCP/IP.
For some reason, Unix does not seem to provide a notification process about the socket or pipe closing the
Signal, or it may be that the CPU is known to be limited. In short, when the other side closes, one executes recv () or read (),
Return immediately to 1, when the value of the global variable errno is 115, the corresponding Sys_errlist[errno]
As "Connect refused" (refer to/usr/include/sys/errno.h). So, on the
for (;;) In the. Select () block, when something is readable, be sure to check the recv () or
The return value of Read () returns 1 when the processing of the local socket is to be turned off, otherwise select () will
Always thought there was something to read, and the result was a few of the CPU broken pins. Do not believe you can try: disorderly
Check recv () Return the result, and will receive the East (actually did not receive) write to the standard output ...
Similar problems arise in the programming of well-known pipelines. Specific treatment See my book: Release a useful
Socket client-side source code.
As for the initiative to write the socket when the other side suddenly closed processing can simply capture the signal sigpipe and make
The corresponding shutdown of the local socket and so on processing. Sigpipe's explanation is: write a pipeline without readers.
Do not repeat here, please detailed man signal.
The above is the CPU in the TCP/IP data transmission Experiment accumulated experience, if there are errors and omissions, please bombard it.
Alas, yesterday in the hacker district was a bunch of grandchildren blew almost no short circuit. ren CPU (Pentium Heart) Z80
Supplemental to the application of select in asynchronous (non-blocking) connect, when you first started socket programming
I've been using a blocking connect, and the problem with non-blocking connect is that the proxy scan
and the proposed hehe
Through online and netizens exchange and find related FAQs, finally know how to solve this problem. Same
A select can be a good solution to this problem. The general process is this:
1. Set the open socket to non-blocking and use FCNTL (socket, F_SETFL, o_ndelay) to finish
(Some systems are also available with Fnedlay).
2. Connect call, then return-1, but errno is set to einprogress, meaning that connect still
In progress has not yet been completed.
3. Set the open socket into a monitored writable (note not readable) collection of files to monitor with select
If it can be written, use
GetSockOpt (socket, sol_socket, so_error, &error, sizeof (int));
To get the value of the error, and if it is zero, connect succeeds.
In many Unix versions of the Proxyscan program you can see a similar process, in addition to the Solaris Essentials
There is a universal Connect module with timeout parameters in the programming Tips section.
Linux c Select () function