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