Socket programming Practice (one)--select I/O multiplexing

Source: Internet
Author: User
Tags socket error

Select function

Man-page

/* According to POSIX.1-2001 */#include <sys/select.h>/* according to earlier standards */#include <SYS/TIME.H&G t; #include <sys/types.h> #include <unistd.h>int select (int Nfds, fd_set *readfds, Fd_set *writefds,           fd_ Set *exceptfds, struct timeval *timeout);


Select instructions for use:

? Monitor Readfds to see if read is blocked, and note that even end-of-file,fd is readable.

? Monitor Writefds will not be blocked if you read and write.

? Monitor for EXCEPTFD If an exception has occurred. Primarily used to read OOB data, exceptions do not refer to errors.

? Note that when a set of interfaces goes wrong, it becomes both readable and writable.

? If there is a state change, the other FD is zeroed out, and only those that have changed are kept in place to indicate which of the set has changed state.

? Parameter n is the value of the FD with the maximum value plus 1 for all FD in all set

Select Implementation Description:

An IO descriptor that is interesting to the kernel user by parameters when calling Select

IO Status of concern: input, output, or error

Caller Wait Time

After returning the kernel tells the caller that multiple descriptors are ready

What descriptors have changed

Invoke read-write operation on prepared descriptor after call returns

Do not care about the descriptor set passed NULL

Parameter description:

1.nfds is the highest-numbered file descriptor in any of the three Sets,plus 1.

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

3.timeout[The maximum wait time from the start of a call to a select return]

Timeval structure:

struct Timeval {    long    tv_sec;    /* seconds */    longtv_usec;    /* microseconds */};

Description

Some calls use 3 empty sets, N is 0, and 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 timeout, so for better portability, timeout needs to be 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  file  descriptors  contained  in  the   three  returned descriptor sets  (That is, the total number  of bits that are  set  in  readfds,  writefds, &NBSP;&NBSP;EXCEPTFDS)  which  may  be  zero if the timeout  expires before anything interesting happens.  On error, -1  Is returned, and errno is set appropriately; the sets  and   timeout  become  undefined, so do not rely on  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.

Example: (from Man-page)

#include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h>int Main () {    fd_set RfDs;    struct Timeval TV;    int retval;    /* Watch stdin (FD 0) to see if it has input. *    /Fd_zero (&RFDS);    Fd_set (0, &rfds);    /* Wait up to five seconds. */    tv.tv_sec = 5;    tv.tv_usec = 0;    retval = Select (1, &rfds, NULL, NULL, &TV);    /* Don ' t rely on the value of TV now! */    if (retval = =-1)        perror ("select ()");    else if (retval)    {        if (Fd_isset (0,&rfds))        {            char buf[bufsiz];            Cin >> BUF;            cout << "FD 0 is ok! And you input is: "<< buf << Endl;        }    }    else    {        printf ("No data within five seconds.\n");    }    Exit (exit_success);}


Select Implementation principle

Fd_set is a bit vector and each bit represents a descriptor


int fd_isset (int fd, fd_set *fdset);//test whether a descriptor is in the set void fd_clr (int fd, fd_set *fdset);//Remove a descriptor from the collection void fd_set (int fd , Fd_set *fdset);//Add a descriptor to the set void Fd_zero (Fd_set *fdset);//Empty Descriptor Collection

After executing the following code :

    Fd_set Readset;    Fd_set Writeset;    Fd_zero (&readset);    Fd_zero (&writeset);    Fd_set (0,&readset);    Fd_set (3,&readset);    Fd_set (1,&writeset);    Fd_set (2,&writeset);    Select (4,&readset,&writeset,null,null);


Fd_set Description:

? You can put the same descriptor in both the read and write collections

? When reading and writing are ready, the count of return values is added 1 times

? Three states of normal files always return to the prepared state

? Whether blocking IO does not affect the results of select

? If a descriptor is to the end of the file, select returns the status to be ready.

? For a prepared descriptor, the readout length is 0 to reach the end

Practice: Optimize client code with SELECT

#include "commen.h" int main () {int sockfd = mkatcpclient (9001, "127.0.0.1");    Char Sendbuf[bufsiz];    Char Recvbuf[bufsiz];        while (true) {int fdcount = SOCKFD > Stdin_fileno? sockfd+1:stdin_fileno+1;        Fd_set Rdset;        Fd_zero (&rdset);        Fd_set (Sockfd,&rdset);        Fd_set (Stdin_fileno,&rdset);        int nready = SELECT (Fdcount,&rdset,null,null,null);        if (Nready = =-1) {err_exit ("select Error"); }//server end has data readable if (Fd_isset (Sockfd,&rdset)) {//read data from socket int Readcoun            t = Read (sockfd,recvbuf,sizeof (RECVBUF));            if (Readcount = =-1) {err_exit ("read socket error");            } else if (Readcount = = 0)//If End-to-end link {peercloseprint ();            } fputs (Recvbuf,stdout);        memset (recvbuf,0,sizeof (RECVBUF)); }//Data readable on standard input: Send to socket from keyboard reading data       if (Fd_isset (Stdin_fileno,&rdset)); {if (Fgets (sendbuf,sizeof (SENDBUF), stdin)! = NULL) {if (Write (Sockfd,sendbuf,strlen (                SENDBUF)) = =-1)//sent to socket {err_exit ("write error");            } memset (Sendbuf,0,sizeof (SENDBUF));    }}} close (SOCKFD); return 0;} /** Description: Server-side code (ECHO server) */

Attached -commen.h Source code

#ifndef commen_h_included#define commen_h_included#include <unistd.h> #include <signal.h> #include < errno.h> #include <fcntl.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/stat.h > #include <sys/ipc.h> #include <sys/shm.h> #include <sys/msg.h> #include <sys/sem.h># Include <sys/socket.h> #include <sys/select.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdio.h> #include    <stdlib.h> #include <iostream>using namespace std;void err_exit (std::string str) {perror (Str.c_str ()); Exit (exit_failure);}    void Peercloseprint (std::string str = "Peer Connect closed") {cout << str << Endl; _exit (0);} Return a socket that has start listened.int mkatcpserver (int serverport, int backlog = somaxconn) {int sockfd = sock    ET (af_inet,sock_stream,0); if (SOCKFD = =-1) {Err_exit ("socket error");    }//add address reused int on = 1; if (setsockopt (sockfd,sol_socket,so_reuseaddr,&on,sizeof (on)) = =-1) {err_exit ("setsockopt so_reuseaddr err    or ");    }//band a local address and port struct sockaddr_in serveraddr;    serveraddr.sin_family = af_inet;    Serveraddr.sin_port = htons (ServerPort);    SERVERADDR.SIN_ADDR.S_ADDR = Inaddr_any; Band an any IP address if (bind (SOCKFD, struct sockaddr *) &serveraddr,sizeof (serveraddr)) = =-1) {Err_    Exit ("bind error");    }//start to listen.    if (listen (sockfd,backlog) = =-1) {Err_exit ("Listen error"); } return SOCKFD;} Return a socket that has connected to Server.int mkatcpclient (int serverport, string serveripaddr) {//first. Create    a socket int sockfd = socket (af_inet,sock_stream,0);    if (SOCKFD = =-1) {Err_exit ("socket error"); }//second.    Connect to a server struct sockaddr_in serveraddr; Serveraddr.sin_family= Af_inet;    Serveraddr.sin_port = htons (ServerPort);    SERVERADDR.SIN_ADDR.S_ADDR = inet_addr (Serveripaddr.c_str ());    if (Connect (SOCKFD, struct sockaddr *) &serveraddr,sizeof (serveraddr)) = =-1) {err_exit ("connect error"); } return SOCKFD;}    void oncatchsigchld (int signalnumber) {int ret = 0; while (ret = Waitpid ( -1,null,wnohang)! =-1));}    ssize_t readn (int fd,void *buf,size_t count) {size_t nleft = count;    ssize_t nread = 0;    Char *ptr = Static_cast<char *> (BUF); while (Nleft > 0) {if (nread = Read (fd,ptr,nleft)) < 0) {//a bit of things are not read if (nLe  FT = = count) {return-1;  Error} else {break;  Error, return amount read so far}} else if (nread = = 0) {break;        EOF} nleft-= Nread;    PTR + = nread; } return count-nleft;} ssize_t writen (int fd, const void *buf, size_t count) {size_t nleft = count;    ssize_t Nwritten;    const char *ptr = static_cast<const char *> (BUF); while (Nleft > 0) {if (Nwritten = Write (fd,ptr,nleft)) < 0) {//A little something is not written if            (Nleft = = count)  {return-1;  Error} else {break;  Error, return amount write so far}} else if (Nwritten = = 0) {break;        EOF} nleft-= Nwritten;    PTR + = Nwritten; } return Count-nwritten;}    Just looking at the data in the network is not really taking it away: msg_peekssize_t recv_peek (int fd, void *buf, size_t count) {int nread = 0;    If there is an error reading the network data, continue reading while ((Nread = recv (fd,buf,count,msg_peek)) = =-1); return nread;}    ssize_t readline (int fd, void *buf, size_t maxline) {char *pbuf = (char *) buf;    int nleft = Maxline; while (true) {//views the data in the buffer, does not really take away int ntestread = Recv_peek (fd,pbuf,nleft);        Detects if the read data contains ' \ n ';                If so, read it all out for (int i = 0; i < Ntestread; ++i) {if (pbuf[i] = = ' \ n ') {  True to take the data from the buffer if (READN (fd,pbuf,i+1)! = i+1) {err_exit ("Readn                Error ");                } else {return i + 1;        }}}//If the read buffer does not have ' \ n '///If read out: The number of read morals is greater than the maximum number of rows, then do exception handling if (Ntestread > Nleft)        {exit (exit_failure); } nleft-= Ntestread;        If the buffer does not have ' \ n ', then the remaining data will be read if (READN (fd,pbuf,ntestread)! = Ntestread) {exit (exit_failure);    } PBuf + = Ntestread; } return-1;} #endif//commen_h_included

Socket programming Practice (one)--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.