Socket programming Practice (8)--SELECT-I/O multiplexing

Source: Internet
Author: User
Tags socket error

introduction of five I/O models

(1) blocking i/o[default]


When the upper app invokes the RECV system call, if the peer does not send data (there is no data in the Linux kernel buffer), the upper application Application1 will block, and when the peer sends the data, the Linux kernel recv-side buffer data arrives, The kernel will copy the data to the user space. Then the upper app is unblocked and the next step is done.

(2) non-blocking i/o[less use]


The upper app app sets the socket to non-blocking mode, and then loops through the RECV function to accept the data. If the buffer does not have data, the upper application will not block, the recv return value is-1, the error code is ewouldblock.

The upper application constantly polls for no data coming. cause upper application busy waiting. Consumes CPU heavily. Therefore, non-blocking modes are seldom used directly. Small application range, general and IO multiplexing with use .

(3) I/O multiplexing [focus]


The upper application app calls other IO multiplexing systems called SELECT (which is supported by the Linux kernel, avoids the app busy waiting), and polls the status changes of the file descriptor; When select manages a file descriptor with no data (or if the state does not change), the upper application blocks.

The advantage is that the select mechanism can manage multiple file descriptors; Select can be regarded as a manager, with Select to manage multiple IO, once detected by an IO or multiple io, when we feel the event occurs, the Select function will return, the return value is the number of detected events. You can then use select-related API functions to manipulate specific events.

The Select function can set the wait time to avoid the long-term zombie application of the top app.

Compared to the blocking IO model, the Select I/O multiplexing model is equivalent to blocking ahead of time. When there is data coming, the call to Recv will not block.

(4) Signal-driven i/o[not commonly used]


The upper application app establishes the SIGIO Signal processing program. When the buffer data arrives, the kernel sends a signal to the upper application app; When the upper app receives the signal, the RECV function is called, and the recv function is generally not blocked because the buffer has data.

This is used for the model is relatively small, belonging to the typical "pull mode (upper application passive to the Linux kernel space pull data)". That is: the upper application app, need to call the RECV function to pull the data in, there will be time delay, we can not avoid the delay, there is a new signal generation.

(5) Asynchronous i/o[are not commonly used]


The upper application app calls the Aio_read function and submits a buffer buf for the application layer, which is not blocked when the call is complete . The upper app app can continue other tasks; When the TCP/IP protocol buffer has data, Linux actively copy the kernel data to the user space. Then send a signal to the upper app app and tell the app that data arrives and needs to be processed!

Asynchronous IO is a typical "push mode", is the most efficient mode , the upper-level application app has the ability of asynchronous processing (with the support of the Linux kernel, while processing other tasks, but also support IO communication, Functions like the completion port under the Windows platform IOCP).

select-i/o multiplexing

#include <sys/select.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h>int Select (int Nfds, fd_set *readfds, Fd_set *writefds,           fd_set *exceptfds, struct timeval *timeout);

Select implements the function of a manager: using Select to manage multiple Io, once one IO or multiple IO detects events of interest to us, select returns, the return value is the number of detected events, and the 2nd to 4th parameter returns those IO sent events. This allows us to traverse these events and then handle them;

Parameters:

Nfds:is the highest-numbered file descriptor in any of the three sets,plus 1[read, write, exception in the collection of the largest descriptor +1].

fd_set[four macros to operate on Fd_set]

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);

timeout[The maximum wait time from the start of the call to the select Return, note that this refers to the relative time]

Timeval structure: struct timeval{    long    tv_sec;    /* seconds */    longtv_usec;    /* microseconds */};//some calls use 3 empty set, N is 0, a non-empty timeout to achieve a more accurate sleep.

in Linux, the Select function changes the timeout value to indicate the time remaining , but many implementations do not change the timeout.

For better portability, timeout is usually re-assigned to the initial value in the loop.

Timeout value:

timeout== NULL

Infinite wait, returned by signal interruption-1, errno set to Eintr

Timeout->tv_sec = = 0 && tvptr->tv_usec = 0

Do not wait for immediate return

Timeout->tv_sec! = 0 | | Tvptr->tv_usec! = 0

Waits for a specific length of time, time-out returns 0

return value:

On success, select () and Pselect () return the number of the file descriptors contained in

The three returned descriptor sets (That's, the total number of bits it is set in

Readfds, Writefds, Exceptfds) which may is zero if the timeout expires before anything

interesting happens. On error, 1 are returned, and errno is set appropriately; The sets

and timeout become undefined, so does not rely in their contents after an error.

If successful, returns the number of descriptors in all sets, returns 0 if time-out, or 1 if an error occurs.

Read, write, abnormal event occurrence conditions

Readable:

Can write:

Abnormal:

The set interface buffer has data readable (the connected peer sends the data over, fills the local socket buffer, so that the socket buffer has data readable);

The socket send buffer has space to hold the data (because most of the time the send buffer is not full, so we generally do not care about this event);

The socket interface has out-of-band data;

The read half (opposite end) of the connection is closed (close is called), i.e. the fin segment is received, and the read operation returns 0;

The write half of the connection is closed. After receiving the RST segment, the write operation is called again;

If the listener is a socket interface, the completed queue is not empty;

The socket interface has an error to be processed, and the error can be obtained by getsockopt specifying the SO_ERROR option;

&NBSP;

/** Example 1: Using Select to improve the Echoclient function of the client side of the Echo Echo server allows multiple file descriptors to be monitored simultaneously in a single process; **/void echoclient (int sockfd) {char buf[    512];    Fd_set RSet;    Ensure that the standard input is not redirected int fd_stdin = Fileno (stdin); int maxfd = Fd_stdin > sockfd?    FD_STDIN:SOCKFD;        while (true) {Fd_zero (&rset);        Fd_set (Fd_stdin, &rset);        Fd_set (SOCKFD, &rset);        int nready = SELECT (maxfd+1, &rset, NULL, NULL, NULL);        if (Nready = =-1) err_exit ("select Error");        else if (Nready = = 0) continue;             /** nready > 0: Readable event detected **/if (Fd_isset (Fd_stdin, &rset)) {memset (buf, 0, sizeof (BUF));            if (fgets (buf, sizeof (BUF), stdin) = = NULL) break;        if (writen (SOCKFD, buf, strlen (buf)) = =-1) err_exit ("Write socket error");            } if (Fd_isset (SOCKFD, &rset)) {memset (buf, 0, sizeof (BUF)); int readbytes = ReadLine (sockfd, buf, siZeof (BUF));                if (readbytes = = 0) {cerr << "server connect closed ..." << Endl;            Exit (Exit_failure);            } else if (readbytes = =-1) err_exit ("Read-line socket Error");        cout << buf; }    }}
/** Example 2: Use Select to improve the server side of the Echo Echo server to accept the connection and process the connection part of the code: so that the single process can handle the multi-client connection, for the single-core CPU,    Single process using select processing connection and listening sockets its efficiency is not necessarily worse than multi-process/multithreading performance; **/struct sockaddr_in clientaddr;    Socklen_t Addrlen;    int maxfd = LISTENFD;    Fd_set RSet;    Fd_set Allset;    Fd_zero (&rset);    Fd_zero (&allset);    Fd_set (LISTENFD, &allset);    Used to save the connected client socket int Client[fd_setsize];    for (int i = 0; i < fd_setsize; ++i) client[i] = 1;   int maxi = 0;        Used to hold the largest non-idle position for select return after the array is traversed while (true) {rset = Allset;        int nready = SELECT (maxfd+1, &rset, NULL, NULL, NULL);            if (Nready = =-1) {if (errno = = eintr) continue;        Err_exit ("select Error");        }//nready = = 0 indicates a timeout, but here is an else if (Nready = = 0) Continue that will not occur;            if (Fd_isset (LISTENFD, &rset)) {Addrlen = sizeof (CLIENTADDR); int CONNFD = accept (LISTENFD, struct sockaddr *) &clientaddr, &Addrlen);            if (CONNFD = =-1) err_exit ("Accept error");            int i;                    for (i = 0; i < fd_setsize; ++i) {if (Client[i] < 0) {                    Client[i] = CONNFD;                    if (i > Maxi) maxi = i;                Break                 }} if (i = = fd_setsize) {Cerr << "too Many clients" << Endl;            Exit (Exit_failure);                 }//Print client IP address and port number cout << "Client information:" << Inet_ntoa (CLIENTADDR.SIN_ADDR)            << "," << Ntohs (clientaddr.sin_port) << Endl;            Put the connection socket interface into Allset and update the MAXFD fd_set (CONNFD, &allset);            if (Connfd > maxfd) maxfd = CONNFD;        if (--nready <= 0) continue; }/** if it is a connected socket interface, a readable event occurs **/for (int i = 0; I <= maXi  ++i) if ((client[i]! =-1) && Fd_isset (Client[i], &rset)) {char buf[512]                = {0};                int readbytes = ReadLine (Client[i], buf, sizeof (BUF));                if (readbytes = =-1) err_exit ("ReadLine error");                    else if (readbytes = = 0) {cerr << "client connect closed ..." << Endl;                    FD_CLR (Client[i], &allset);                    Close (Client[i]);                Client[i] =-1;                }//Note here: After the server obtains the data from the client, it does not immediately return to the back,//instead waits four seconds before returning to sleep (4);                cout << buf;                if (Writen (Client[i], buf, readbytes) = =-1) err_exit ("writen error");            if (--nready <= 0) break; }    }

For full source code, please refer to:

http://download.csdn.net/detail/hanqing280441589/8486517

Socket programming Practice (8)--SELECT-I/O multiplexing

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.