Network Programming api-(I/O multiplexing function)

Source: Internet
Author: User
Tags epoll strcmp htons

Io multiplexing is one of the IO models in Linux, and IO multiplexing is the process of pre-telling the kernel to monitor the IO conditions so that once the kernel discovers that one or more of the IO conditions specified by the process is in place, it is processed through the process process, thus not blocking on a single IO. In Linux, there are three interface functions for IO multiplexing, select, poll, and Epoll.


1. Select function

#include <sys/select.h> #include <sys/time.h>int select (int Nfds, fd_set *readfds, Fd_set *writefds, Fd_set * Exceptfds, struct timeval *timeout); return: If a ready descriptor is the number, timeout is 0, error 1

The Nfds parameter specifies the number of listener file descriptors, usually set to the maximum of all descriptor listeners, plus 1 because the file descriptor starts at 0. Readfs, Writefds, and Exceptfds correspond to a set of event file descriptors, such as readable, writable, and anomalous, respectively, when Select is called, and the 3 parameters are passed to the file descriptor of interest, and when the Select function returns, The kernel notifies the application by modifying them that the file descriptor is ready.

The Fd_set struct contains an array of shapes, each of which is marked with a file descriptor, and the number of file descriptors Fd_set accommodates is specified by Fd_setsize, which limits the maximum number of file descriptors that select can handle simultaneously. Use some macros to manipulate the bits in the FD_SET structure:

#include <sys/select.h>fd_zero (fd_set *fdset);/* Clear fdset All flag bits */fd_set (int FD, fd_set fdset);/* Set fdset flag bit FD */fd _CLR (int fd, fd_set fdset);/* Clear Fdset flag bit FD */int fd_isset (int fd, fd_set *fdset);/* Test Fdset bit FD is set */
The timeout parameter is used to set the time-out for Select, which is a timeval struct-type pointer, and the pointer parameter is the time that the kernel will modify it to tell the application select how long it has waited. However, we cannot fully trust the timeout value returned by the select call, such as when the value of timeout is indeterminate after the call fails.

struct Timeval{long tv_sec;//number of seconds long tv_usec;//microseconds};

Select provides a subtle timing scheme that if a member of Timeval is assigned a value of 0, select will return immediately, and if timeout is null, then select will block until a file descriptor is ready. When select succeeds returns the total number of file descriptors ready, if no descriptor is ready within the timeout period, select returns 0,select failure to return 1 and set errno. If the program receives a signal during the select Wait, the Select returns 1 immediately and sets errno to Eintr.

Select Disadvantages:

Every time I call Select, we need to copy the FD collection from the user state to the kernel state, which is very expensive when FD is very large.

Every time I call Select, I need to traverse all the FD that is passed in the kernel, which is also very expensive when FD is very large

L Select supports a small number of file descriptors, which defaults to 1024

/** * Select Test case */#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ socket.h> #include <sys/select.h> #include <netinet/in.h> #include <arpa/inet.h> #include < string.h> #define ERR_SYS (msg) do {perror (msg); exit ( -1);} and (0) #define ERR_EXIT (msg) do {fprintf (stderr, msg); Exi T (-1); } while (0) #define ERR_INFO (msg) does {fprintf (stderr, msg);} while (0) int main (int argc, char *argv[]) {if (argc! = 3) Err_exi T ("Usage:./a.out IP port.\n"), int port = atoi (argv[2]), int listenfd, connfd;struct sockaddr_in servaddr;if ((LISTENFD = So Cket (af_inet, Sock_stream, 0)) < 0) Err_sys ("socket"); bzero (&servaddr, sizeof (SERVADDR)); servaddr.sin_family = Af_inet;servaddr.sin_port = htons (port), if (Inet_pton (Af_inet, argv[1], &servaddr.sin_addr) < 0) Err_sys ("inet_ Pton "), if (Bind (LISTENFD, (struct sockaddr *) &servaddr, sizeof (SERVADDR)) < 0) Err_sys (" bind "), if (Listen ( LISTENFD, 5) < 0) Err_sys ("LISTENFD"); if (connfd = Accept (lisTENFD, NULL, NULL)) < 0) Err_sys ("accept"); Fd_set Read_fd;fd_set except_fd; Fd_zero (&AMP;READ_FD); Fd_zero (&AMP;EXCEPT_FD); char buf[1024];while (1) {memset (buf, 0, sizeof (BUF));/* re-read_fd and Except_ before each call to select FD sets the file description floating CONNFD, because after the event occurs, * File Description descriptor will be modified by the kernel */fd_set (CONNFD, &AMP;READ_FD); Fd_set (CONNFD, &AMP;EXCEPT_FD), if (select (CONNFD + 1, &read_fd, NULL, &AMP;EXCEPT_FD, NULL) < 0) Err_sys ("select") ;/* For readable events, use the normal recv function to read data */if (Fd_isset (CONNFD, &read_fd)) {if (recv (CONNFD, buf, sizeof (BUF)-1, 0) < 0) {Err_ Info ("recv error\n"); continue;} if (!strcmp (buf, "exit")) {printf ("I had got the exit, I'll go out! Bye!\n "); break;} else{printf ("recv:%s\n", buf);}} /* For exception events, use the Recv function with the MSG_OOB flag to go out of band Data */if (Fd_isset (CONNFD, &except_fd)) {if (recv, CONNFD, sizeof (BUF)-1, buf OOB) < 0) {err_info ("recv error\n"); continue;} printf ("Recv:%s\n", buf);}} Close (CONNFD); close (LISTENFD); return 0;}


2. Poll function

#include <poll.h>int poll (struct POLLFD *fds, nfds_t nfds, int timeout); Returns: If a ready descriptor is the number, timeout is 0, error 1

Poll system calls are similar to select, and they also poll for a certain number of file descriptors within a certain amount of time to test for a ready person. The Nfds parameter specifies the size of the FDS for the Listener event collection, timeout specifies the timeout value for poll, in milliseconds, and when timeout is-1, the poll call will block until an event occurs, and the poll call returns immediately when timeout is 0 o'clock.

POLLFD Structural Body:

struct Pollfd{int fd;/* file descriptor */short events;/* registered event */short revents;/* The actual event, with kernel padding */};

Types of events supported by poll:

/** * Poll test cases while receiving data from clients and reading data from standard input */#include <stdio.h> #include <stdlib.h> #include <unistd.h># Include <sys/socket.h> #include <sys/poll.h> #include <netinet/in.h> #include <arpa/inet.h># Include <string.h> #define ERR_SYS (msg) do {perror (msg), exit ( -1), and (0) #define ERR_EXIT (msg) do {fprintf (stde RR, MSG); Exit (-1); } while (0) #define ERR_INFO (msg) does {fprintf (stderr, msg);} while (0) int main (int argc, char *argv[]) {if (argc! = 3) Err_exi T ("Usage:./a.out IP port.\n"), int port = atoi (argv[2]), int listenfd, connfd;struct sockaddr_in servaddr;if ((LISTENFD = So Cket (af_inet, Sock_stream, 0)) < 0) Err_sys ("socket"); bzero (&servaddr, sizeof (SERVADDR)); servaddr.sin_family = Af_inet;servaddr.sin_port = htons (port), if (Inet_pton (Af_inet, argv[1], &servaddr.sin_addr) < 0) Err_sys ("inet_ Pton "), if (Bind (LISTENFD, (struct sockaddr *) &servaddr, sizeof (SERVADDR)) < 0) Err_sys (" bind "), if (Listen ( LISTENFD, 5) < 0) Err_sys ("LISTENFD");(CONNFD = accept (LISTENFD, NULL, NULL)) < 0) Err_sys ("accept"), struct POLLFD poll_fd[2];p oll_fd[0].fd = connfd;poll_fd [0].events = POLLIN;POLL_FD[1].FD = stdin_fileno;poll_fd[1].events = Pollin;char Buf[1024];int runing = 1; #define MAXEVEN TS 2while (runing) {memset (buf, 0, sizeof (BUF)), if (poll (POLL_FD, Maxevents,-1) < 0) Err_sys ("poll"); int i, SOCKFD, ret; for (i = 0; i < maxevents; i++) {if (Poll_fd[i].revents & pollin) {sockfd = poll_fd[i].fd;if (sockfd = = CONNFD) {if (ret = Recv (SOCKFD, buf, sizeof (BUF)-1, 0)) <= 0) {if (Ret < 0) err_info ("recv error\n"); else{printf ("The client host is T Erminal. I'll go tou! bye!! \ n "); runing = 0;}} if (!strcmp (buf, "exit")) {printf ("I had got the exit, I'll go out! Bye!\n "); runing = 0;} else{printf ("recv:%s\n", buf);}} else if (sockfd = = Stdin_fileno) {scanf ("%s", buf), if (Send (CONNFD, buf, strlen (BUF), 0) < 0) {err_info ("send Error");}}} }close (CONNFD); close (LISTENFD); return 0;}

3. Epoll Series function

Epoll is a Linux-specific IO multiplexing function that differs greatly in implementation and use from select and poll, and first, Epoll uses a set of functions to complete the operation, rather than a single function. Second, Epoll places events on the user's care file descriptor in an event table on the kernel, eliminating the need to repeat the incoming file Descriptor collection event table for each invocation, like Select and poll. However, Epoll needs to use an additional file descriptor to uniquely identify this event table in the kernel, which is created using the following epoll_create function

#include <sys/epoll.h>int epoll_create (int size); return: The descriptor for the created kernel event table was returned successfully, error 1

The size parameter now does not work, just give the kernel a hint to tell it how big the kernel table needs to be, and the file descriptor returned by the function will be used as the first parameter of all other Epoll functions to specify the kernel event table to access. Using the EPOLL_CTL function to manipulate the kernel event table

#include <sys/epoll.h>int epoll_ctl (int opfd, int op, int fd, struct epoll_event *event);

Return: Successful return 0, error 1

The FD parameter is the file descriptor to be manipulated, op specifies the type of operation, there are 3 types of operation

L Epoll_ctl_add: Register an event on the FD in the event table

L Epoll_ctl_mod: Modify the registration event on the FD

L Epoll_ctl_del: Delete the registration time on FD Love you

event specifies the type of events, which is the epoll_event struct pointer type

struct epoll_event{__uint32_t events;/* epoll event */epoll_data_t data;/* user data */};

Where events describes the event type, Epoll supports the same event type and poll, and the macro that represents the Epoll event type is the poll corresponding macro plus "E", such as the Epoll data-readable event is Epollin, But Epoll has two additional event types,-epollet and Epolloneshot, which are critical for efficient operation, and data is used to store user data whose type epoll_data_t is defined as follows:

typedef Union epoll_data{void *ptr;int fd;uint32_t u32;uint64_t u64;} epoll_data_t;

Epoll_data_t is a consortium in which 4 members use the most FD, which specifies the target file descriptor that the event is subordinate to, and the PTR member can use to specify FD-related user data, but since opoll_data_t is a consortium, we cannot work with both FD and PTR. If you want to associate the file descriptor Hum User data for fast data access, you can use only other means, such as discarding the FD member, and the user data pointed to by the PTR pointer contains the FD

#include <sys/epoll.h>int epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout); Return: Number of file descriptors successfully returned, error 1

The timeout parameter has the same meaning as the timeout parameter of the poll interface, and the maxevents parameter specifies the maximum number of events to listen on, which must be greater than 0.

Epoll_wait If an event is detected, all ready events are copied from the Kernel event table (specified by EPFD) to the array specified in events, which is used only to epoll_wait the ready events detected by the event. Rather than a parameter array like Select and poll, which passes events for user registration, there is a ready event for the output kernel to detect, which greatly improves the efficiency of the application index-ready file descriptor.

/** * Epoll Test Case * When file name is io_epoll.c, compile option gcc io_epoll.c error, hint unknow type name epoll_event * When file name io_epoll.cpp, compile option gcc IO _epoll.cpp or g++ io_epoll.c can * * #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/epoll.h> #include <netinet/in.h> #include <arpa/inet.h> #include <fcntl.h> #include <string.h> #define ERR_SYS (msg) do {perror (msg); exit (-1);} while (0) #define ERR_EXIT (msg) do {fprintf (stderr, msg), Exit ( -1), and (0) #define ERR_INFO (msg) do {fprintf (stderr, MS g); } while (0) #define Maxevents 5void addfd (int epollfd, int fd) {Epoll_event event;event.data.fd = Fd;event.events = Epollin;e Poll_ctl (EPOLLFD, Epoll_ctl_add, FD, &event);} int main (int argc, char *argv[]) {if (argc! = 2) err_exit ("Usage:./a.out port\n"); int port = atoi (argv[1]); int listenfd, con Nfd;struct sockaddr_in Servaddr;bzero (&servaddr, sizeof (SERVADDR)); servaddr.sin_family = AF_INET;servaddr.siN_port = htons (port), servaddr.sin_addr.s_addr = Htonl (Inaddr_any), if (LISTENFD = socket (af_inet, sock_stream, 0)) < 0 Err_sys ("socket"), if (Bind (LISTENFD, (struct sockaddr *) &servaddr, sizeof (SERVADDR)) < 0) Err_sys ("bind"); Listen (LISTENFD, 5) < 0) Err_sys ("Listen"); Epoll_event events[maxevents];int epollfd;if ((EPOLLFD = Epoll_create (5)) < 0) Err_sys ("Epoll_create"), if ((CONNFD = accept (LISTENFD, NULL, NULL)) < 0) Err_sys ("accept"), ADDFD (EPOLLFD, CONNFD); ADDFD (EPOLLFD, stdin_fileno); int runing = 1;while (runing) {int I, CNT = epoll_wait (EPOLLFD, events, maxevents,-1) Char buf[1024];for (i = 0; i < cnt; i++) {int sockfd = events[i].data.fd;if (sockfd = = Stdin_fileno) {scanf ("%s", buf); if ( Send (CONNFD, buf, strlen (BUF), 0) < 0) {err_info ("Send error\n");}}  else if (sockfd = = connfd) {int Ret;bzero (buf, sizeof (BUF)); if (ret = recv (SOCKFD, buf, sizeof (BUF)-1, 0)) <= 0) {if (ret < 0) Err_info ("recv error\n"); else{printf ("The client host is termenal. I'll go out! Bye!\n ");runing = 0;}} else if (!strcmp (buf, "exit")) {printf ("I had got the ' exit ', I'll go out! Bye\n "); runing = 0;} else{printf ("recv:%s\n", buf);}}} Close (CONNFD); close (LISTENFD); return 0;}

Resources:

1, "Linux High Performance Server Programming" The 9th Chapter IO multiplexing


Network Programming api-(I/O multiplexing function)

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.