Long time useless I/O multiplexing, feel almost the same is almost forgotten. I remember I spent a lot of time just learning I/o multiplexing. But because that will not be too fond of blogging, leading to spend a lot of time to make clear things, still very easy to forget. As the saying goes, the eye times than hand over again, indeed. In later study, no matter how difficult or important the knowledge is. I will try to write down the form of a blog, so that you can use the blog to urge themselves to learn, but also to deepen the understanding of the knowledge of both its beauty, good nonsense not to say.
Basic overview of I/O multiplexing
I/O multiplexing technology is mainly used to listen to multiple socket descriptors at the same time, which makes our program greatly improve performance, such as the following situations will use the I/O multiplexing technology
(1) Procedures need to handle multiple sockets at the same time
(2) client programs need to handle user input and network connection at the same time
(3) TCPServer to handle the listening socket and connection socket at the same time
(4) Server to process TCP and UDP requests at the same time
(5) Server to process multiple ports at the same time
1.select system Call
#include<sys/select.h>intselect(int*readfds*writefds*exceptfds*timeout);
The. NDF parameter specifies the number of descriptive descriptors for the monitored file, which is usually set to the full file descriptor of the Select Listener plus 1.
The. Readfds,writefds,exceptfds parameters point to a readable, writable, and unusual event, where the application is added to the corresponding collection by adding a file descriptor of interest to it, when the select call returns. The kernel will change them to notify the application which file descriptor is ready, timeout is time-out, and the select call successfully returns the number of file descriptive descriptors that are ready
We generally use the following macros for example to access the bits in Fd_set
#include<sys/select.h>FD_ZERO(fd_set *fdset); //清除fdset的全部位FD_SET(int fd,fd_set *fdset);//设置fdset的fd位FD_CLR(int fd,fd_set *fdset);//清除fdset的位fdint FD_ISSET(int//測试fdset的位是否被设置
Document Descriptive Descriptor readiness condition
(1) The socket core receive buffer is greater than or equal to its low water mark So_rcvlowat. At this point we can read the socket without clogging
(2) The other side of the socket communication closes the connection, at which time the read operation of the socket will return 0
(3) A new connection request is on the monitor socket
(4) There are unhandled errors on the socket
(5) Socket core send buffer is greater than its low water level byte So_sndlowat
(6) Socket use non-blocking connect connection after successful or unsuccessful
(7) There are unhandled errors on the socket
Detailed Examples
For example, the following pseudo-code
#include <stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <assert.h>#include <unistd.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <sys/types.h>#include <sys/select.h>intMainvoid){if(ARGC <3) {cout<<"Wrong number of references"<<endl; }Char*ip = argv[1];intPort = atoi (argv[2]);intRET =0;structSockaddr_in address; Bzero (&address,sizeof(adddress)); address.sin_family = af_inet; Inet_pton (AF_INET,IP,&ADDRESS.SIN_ADDR); Address.sin_port = htons (port);intLISTENFD = socket (Af_inet,sock_stream,0); ASSERT (ret! =-1); ret = bind (LISTENFD, (structSOCKADDR *) &address,sizeof(address)); ASSERT (ret! =-1); RET = Listen (LISTENFD,5); ASSERT (ret! =-1);structSockaddr_in client_address; socklen_t len =sizeof(client_address);intCONNFD = Accept (LISTENFD, (structSOCKADDR *) &client_address,&len);if(CONNFD <0) {cout<<"Error"<<endl; Close (LISTENFD); }Charbuf[1024x768]; Fd_set Readfds; Fd_zero (&readfds); while(1) {bzero (buf,1024x768); Fd_set (Connfd,&readfds); ret = SELECT (CONNFD +1, &readfds,null,null,null);if(Ret <0) {cout<<"Error"<<endl; }//Interpreting whether readable events occur if(Fd_isset (Connfd,&readfds)) {ret = recv (Connfd,buf,sizeof(BUF)-1,0);if(Ret <=0) { Break; }cout<<buf<<endl; }} close (LISTENFD); Close (CONNFD);return 0;}
Features of Select
The internal implementation of select calls poll (the following will write, so the reader can skip here, read poll, and look back at this). All of it and poll features the same. Just the function interface is different, essentially the same
Poll features such as the following
(1) Copy the user's incoming POLLFD data (the set of descriptive descriptors of the corresponding select) to the kernel space, the copy process event complexity is O (N)
(2) Each file is queried to describe the state of the descriptor, assuming that there is no ready file descriptive descriptor, then the process will suspend waiting, know that a time-out or device driver wake it again. It then iterates through all the file descriptors to find out the file descriptor of the event. The event complexity is O (N) because it iterates through 2 file-file descriptive descriptors
(3) Copy the acquired data to the user space. Time complexity is also O (N)
Use of 2.poll
Poll prototypes such as the following
#include<poll.h>int poll(struct pollfd *fds,nfds_t nfds,int timeout);
In which FDS is a struct array of type POLLFD, its structure is defined for example the following
struct pollfd{ int fd; //要监听文件描写叙述符 short events;//注冊的事件 short revents;//实际发生的事件,内核填充}
Poll the types of events that can be monitored, such as the following (only those that are often used)
Events |
Descriptive narrative |
Pollin |
Data can be read |
Pollout |
Data can be written |
Pollrdhub |
The TCP connection was closed by the other, or the other party closed the write operation |
Pollhub |
Hang, for example, the write end of the pipe is closed |
Pollerr |
Error |
Nfds the number of descriptive descriptors for a listening file
Timeout is a time-out event
The file Description descriptor returned by index poll
int ret = poll(fds,MAX_EVENT_NUMBER,-1);//必须遍历全部文件描写叙述符找到当中的就绪事件(也能够依据已知的就绪个数进行简单的优化)for(int0;i<MAX_EVENT_NUMBER,i++){ if(fds[i].revents & POLLIN) { int sock = fds[i]; }}
About the characteristics of poll readers can go back to select to see, before it is written, because it is really said that its internal implementation mechanism is the same as the Select, so it is not necessary to write extra
Use of 3.epoll
Epoll is a Linux-specific I/O multiplexing function that differs from other I/O multiplexing in implementation and use.
It uses a set of functions to complete the task, followed by epoll the events on the file descriptor that the user cares about are placed in a kernel event table.
Epoll needs to use an additional file descriptor to uniquely identify the event table in the kernel, and the file description specifier uses epoll_create () to create
#include<sys/epoll.h>int epoll_create(int size);
The size parameter tells the kernel event table how big it needs to be, and the file description descriptor that the function returns. The first parameter that will be used for all subsequent functions
The following function is used to manipulate the kernel event table
#include<sys/epoll.h>int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event);
FD is the descriptive descriptor of the file to be manipulated, the OP parameter specifies the type of operation, and the type of operation is as follows
type of Operation |
detailed description | of the narrative
Epoll_ctl_add |
Register events on FD in the event table |
Epoll_ctl_mod |
Change the Register event on FD |
Epoll_ctl_del |
Delete a register event on FD |
The definition of a epoll_event struct such as the following
struct epoll_event{ _uint32_t events //epoll事件 epoll_data_t //用户数据}
Epoll_data_t is a consortium whose definition is as follows
typedefunion epoll_data{ void *ptr; int fd; uint32_t u32; uint64_t u64;}epoll_data_t
epoll_wait () function
The primary interface of the Epoll event invocation is the Epoll_wait function, which waits for a set of events on a file description descriptor within a timeout event
#include<sys/epoll.h>int epoll_wait(int epfd,struct epoll_event *events,int maxevents,int timeout);
Returns the number of file descriptive descriptors that are ready when the function succeeds
Assuming that the epoll_wait detects a ready event, it assigns all ready events to the second Epoll_event array, which is used only to output the detected ready events. Array parameters that do not want to be poll are used both for incoming user registration events and for outputting kernel-detected events, which greatly reduces the efficiency of the application index file Description descriptor
Use of Epoll
int ret = epoll_wait(epollfd,events,MAX_EVENT_NUMBER,-1);//仅仅需遍历ret个文件描写叙述符for(int0;i<ret;i++){int sockfd = events[i].data.fd;}
特别注意epoll对文件描写叙述符有俩中模式LT和ET。ET是epoll的高效模式
Features of Epoll
Epoll in the kernel implementation is based on each FD on the Russian callback function to achieve, only active FD will actively invoke callback, the other FD will not.
Assuming that all the file descriptors being monitored are basically active, then the Epoll and select or poll gaps are not too large. But if the documented descriptors are only a few active, the epoll is much more efficient than the two of them.
The use and key analysis of Select,poll,epoll under Linux