The difference between Epoll and select in I/O multiplexing, and instances of Epoll and select

Source: Internet
Author: User
Tags add time bind epoll int size socket stdin strlen htons

The Epoll is the poll of the Linux kernel to handle high concurrency and is an enhanced version of the Select/poll for Linux under multiplexed IO interfaces. Here the main talk about the difference between Epoll and the other two, in addition to epoll a simple application of the example said. (a) Epoll has the main difference of Select,poll:

First, compared to select and poll, the greatest advantage of epoll is that it does not decrease efficiency with the increase of the number of monitoring FD;

The implementation of select and poll in the kernel is handled by polling, and the more the FD data is polled, the more natural time is spent.

Third, the implementation of Epoll is based on callbacks, if the FD has the expected event occurs in the callback function to join the Epoll is ready, that is,

says it only cares about the active FD

Four, the kernel/user space copy problem, when the kernel to notify the FD message to user space, Selec and poll adopt the method of memory copy, and Epoll

Shared memory is used in this way.


(ii) Epoll related system calls

the Epoll interface is very simple, with a total of three functions:
one, (1) int epoll_create (int size); Create a handle to the epoll, size is used to tell the kernel how large the number of listeners is, in fact, the capacity of the specified hash table. This parameter differs from the first parameter in select (), giving the value of the fd+1 that is the maximum listener. It should be noted that when the Epoll handle is created, it will occupy an FD value, under Linux if the view/proc/process id/fd/, is able to see the FD, so after the use of Epoll, you must call Close (), or it may cause FD to be exhausted.

(2) int epoll_create (int flags);

In the newer version of Linux, an int epoll_create (int flags) appears; The flags here generally choose Epoll_cloexec, which indicates that the file descriptor is closed when the process is replaced.

two, int epoll_ctl (int epfd, int op, int fd, struct epoll_event* event); The Epoll event registration function, which is the type of event registered to listen on.

The first parameter is the return value of Epoll_create ().
The second parameter represents an action, represented by three macros:
Epoll_ctl_add: Register the new FD to EPFD;
Epoll_ctl_mod: Modify the monitoring events of the registered FD;
Epoll_ctl_del: Delete a fd from the EPFD;
The third parameter is the FD that needs to be monitored,
The fourth parameter is to tell the kernel what to listen for, struct epoll_event structure as follows:

<span style= "FONT-SIZE:18PX;" >struct epoll_event {
  __uint32_t events; 
  epoll_data_t data; 
};

typedef Union EPOLL_DATA {
void *ptr;    Here is a pointer, mainly used to store complex file descriptor
int fd;
__uint32_t u32;
__uint64_t u64;
} Epoll_data_t;</span>

Events can be a collection of several macros:

Epollin: Indicates that the corresponding file descriptor can be read (including a graceful shutdown of the peer socket);
Epollout: Indicates that the corresponding file descriptor can be written;
Epollpri: Indicates that the corresponding file descriptor has an urgent data readable (this should indicate the arrival of out-of-band data);
Epollerr: Indicates an error occurred in the corresponding file descriptor;
Epollhup: Indicates that the corresponding file descriptor is hung up;
Epollet: Set Epoll to edge trigger (edge triggered) mode (default is horizontal trigger), which is relative to the horizontal trigger (level

triggered).
Epolloneshot: Listen to only one event, when the event is monitored, if you still need to continue to listen to the socket, you need to

Time to add this socket to the Epoll queue three, int epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout);

Wait for the event to occur. The parameters events are used to get the collection of event from the kernel, the maxevents tells the kernel how big the events are, this

The value of maxevents cannot be greater than size when creating epoll_create (), parameter timeout is the timeout (in milliseconds, 0 returns immediately, 11

Wait, that is, blocking). The function returns the number of events that need to be processed, such as returning 0 to indicate a timeout.


(iii) Epoll instances

Here, as an example of a simple client-side callback, the program's operating environment is Debian (a distribution version of Linux), from top to bottom is the header file "Net.h", Epoll_server.cpp,select_client.cpp

Server-side: Epoll implementation, the two things are: 1. Wait for the client's link, 2. Receive data from the client and shoot back;

Client: Select implementation, two things to do: 1. Wait for keyboard input, 2. Send data to server side and receive server-side back-up data;

/*****************
@author: Shaosli
@data: 2015/7/28
@funtions: Network file
********************* /
#include <stdio.h>


#ifndef _net_l
#define _net_l

#include <iostream>
# Include <vector>
#include <algorithm>

#include <stdio.h>
#include <sys/types.h >
#include <sys/epoll.h>  //epoll ways file
#include <sys/socket.h>
#include < Fcntl.h>    //block and Noblock

#include <stdlib.h>
#include <error.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h >
#include <signal.h>

using namespace std;


#define HAND_ERROR (msg) do{perror (msg); exit (exit_failure);} while (0)
#endif

Server-side code:

/**************** @data: 2015/7/28 @authour: Shaosli @function: This CPP was used to test Epoll **************************/ #include ".
	/public/net.h "#define MAX_EVENTS 10000 int setblock (int sock) {int ret = FCNTL (sock, F_SETFL, 0);
	if (Ret < 0) hand_error ("Setblock");
return 0;
	} int Setnoblock (int sock)//set non-blocking mode {int ret = FCNTL (sock, F_SETFL, O_nonblock);
	if (Ret < 0) hand_error ("Setnoblock");
return 0;
	} int main () {int listenfd;   LISTENFD = socket (af_inet, sock_stream,0);
	Create a socket stream if (LISTENFD < 0) hand_error ("Socket_create");
	Setnoblock (LISTENFD);
	int on = 1;
		
	if (setsockopt (LISTENFD, Sol_socket, so_reuseaddr, &on, sizeof (ON)) < 0) Hand_error ("setsockopt");
	struct sockaddr_in my_addr;
	memset (&my_addr, 0, sizeof (MY_ADDR));
	my_addr.sin_family = af_inet;   My_addr.sin_port = htons (5188);
	
	Here is host sequeue my_addr.sin_addr.s_addr = inet_addr ("127.0.0.1"); if (bind (LISTENFD, struct sockaddr*) &my_addr, sizeof (MY_ADDR)) < 0) Hand_error ("bind");
	int lisid = Listen (LISTENFD, somaxconn);
		
	if (Lisid < 0)//listen hand_error ("LISTEN");   struct sockaddr_in peer_addr;	
	Used to save client addr socklen_t Peerlen;
	Here are some of the initializations, all about Epoll.
	Vector<int> clients;
	int count = 0;
	int cli_sock = 0;  int EPFD = 0;  Epoll file descriptor int ret_events;  return value of epoll_wait () struct epoll_event Ev_remov, Ev, events[max_events]; Events is used to store the event read from the kernel ev.events = Epollet |   Epollin;
	
	Edge Mode Trigger EV.DATA.FD = LISTENFD;   EPFD = Epoll_create (max_events);  Create Epoll, the return value is epoll file descriptor//EPFD = epoll_create1 (epoll_cloexec);
	New wording if (EPFD < 0) hand_error ("Epoll_create");   int ret = EPOLL_CTL (EPFD, Epoll_ctl_add, LISTENFD, &ev);
	
	
	Add time if (Ret < 0) hand_error ("Epoll_ctl");   while (1) {ret_events = Epoll_wait (EPFD, events, max_events,-1);
		Similar to the Select function, here is the arrival of the wait event. if (ret_events = =-1) {cout<< "ret_events =" &LT;&LT;RET_EVENTS&Lt;<endl;
		Hand_error ("epoll_wait");
			} if (ret_events = = 0) {cout<< "ret_events =" <<ret_events<<endl;
		Continue
		} cout<< "ret_events =" <<ret_events<<endl;
			for (int num = 0; num < ret_events; num + +) {cout<< "num =" <<num<<endl;
			if (events[num].events = = LISTENFD)//client connect;
				{cout<< "Listen sucess and LISTENFD =" <<listenfd<<endl;
				Cli_sock = Accept (LISTENFD, (struct sockaddr*) &peer_addr, &peerlen);
				if (Cli_sock < 0) Hand_error ("accept");
				cout<< "Count =" <<count++;
				printf ("Ip=%s,port =%d\n", Inet_ntoa (PEER_ADDR.SIN_ADDR), peer_addr.sin_port);
				Clients.push_back (Cli_sock);   Setnoblock (Cli_sock);
				Set to non-blocking mode ev.data.fd = Cli_sock; ev.events = Epollin |
				Epollet;
			if (Epoll_ctl (EPFD, Epoll_ctl_add, Cli_sock, &ev) < 0) Hand_error ("Epoll_ctl"); } else if (Events[num].events & Epollin)
			{cli_sock = EVENTS[NUM].DATA.FD;
				if (Cli_sock < 0) hand_error ("Cli_sock");
				Char recvbuf[1024];
				memset (recvbuf, 0, sizeof (RECVBUF));
				int num = Read (Cli_sock, recvbuf, sizeof (RECVBUF));
				if (num = =-1) hand_error ("Read has some problem:");
						if (num = = 0)//stand of client has exit {cout<< "client has exit" <<endl;
						Close (Cli_sock);
						Ev_remov = Events[num];
						Epoll_ctl (EPFD, Epoll_ctl_del, Cli_sock, &ev_remov);
					Clients.erase (Remove (Clients.begin (), Clients.end (), Cli_sock), Clients.end ());
					} fputs (Recvbuf,stdout);
			Write (Cli_sock, Recvbuf, strlen (RECVBUF));
}}} return 0;

 }
Client code:

/**************** @data: 2015/7/18 @authour: Shaosli @function: This is a client **************************/#include ".
	/public/net.h "int main () {int sock;   Sock = socket (af_inet, sock_stream,0);
	
	Create a socket stream if (sock< 0) hand_error ("Socket_create");
	
	struct sockaddr_in my_addr;
	Memset my_addr;
	memset (&my_addr, 0, sizeof (MY_ADDR));
	my_addr.sin_family = af_inet;   My_addr.sin_port = htons (5188);
	This is host sequeue//my_addr.sin_addr.s_addr = htonl (Inaddr_any);
	
	MY_ADDR.SIN_ADDR.S_ADDR = inet_addr ("127.0.0.1");
	int conn = connect (sock, (struct sockaddr *) &my_addr, sizeof (MY_ADDR));
	
	IF (conn! = 0) hand_error ("Connect");
	Char recvbuf[1024] = {0};
	Char sendbuf[1024] = {0};
	Fd_set RSet;     
	
	Fd_zero (&rset);
	int nready = 0;
	int maxfd;
	int stdinof = Fileno (stdin);
	if (stdinof > sock) maxfd = stdinof;

	else maxfd = sock; while (1) {//select returned after the original to be detected but still not ready for the description of the word clear 0. So each time you call Select, you need to reset the description character to be detected fd_set (sock, &rset);
		Fd_set (stdinof, &rset); 
		Nready = Select (maxfd+1, &rset, NULL, NULL, NULL);
		cout<< "Nready =" <<nready<<endl;
		if (Nready = =-1) break;
		else if (Nready = = 0) continue;
			else {if (Fd_isset (sock, &rset))//detects if sock is already in the collection RSet.  {int ret = read (sock, recvbuf, sizeof (RECVBUF));
				Read Data if (ret = =-1) hand_error ("read");
					else if (ret = = 0) {cout<< "Sever has close" <<endl;
					Close (sock);
				Break    } else {fputs (recvbuf,stdout);
				Output Data memset (recvbuf, 0, strlen (recvbuf)); }} if (Fd_isset (stdinof, &rset))//Detect stdin If the file descriptor is inside the collection {if (fgets (sendbuf, sizeof (SENDBUF), STDI   n) = NULL) {int num = write (sock, SendBuf, strlen (SENDBUF));
					Write Data cout<< "sent num =" <<num<<endl;
				memset (sendbuf, 0, sizeof (SENDBUF));
}}}} return 0;



 }
The code has been tested on my own system.


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.