Linux Network Programming IO multiplexing

Source: Internet
Author: User
Tags assert epoll int size htons

Refer to "Linux High Performance Server Programming"

When dealing with multiple connections under Linux, it is inefficient to use only multithreading and raw socket functions

Then there is the SELELCT poll Epoll and other IO multiplexing functions.

Epoll IO multiplexing with optimal performance is discussed here

The user will need to focus on the socket connection using the IO multiplexing function into an event table, which is processed whenever there is one or more socket connections in the event table with read and write requests

The event table is identified with an additional file descriptor. The file descriptor is created using the Epoll_create function

#inlclude <sys/epoll.h>

int epoll_create (int size); The size parameter does not currently work

Manipulating event tables using the EPOLL_CTL function for control

The operation type has the following 3

Epoll_ctl_add Epoll_ctl_mod Epoll_ctl_del

Wait for events on the event table to use Epoll_wait () during a time-out period;

The function example is as follows:

#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include < string.h> #include <fcntl.h> #include <stdlib.h> #include <sys/epoll.h> #include <pthread.h > #define Max_event_number 1024#define buffer_size 10int setnonblocking (int fd) {int old_option = Fcntl (FD, F_GETF    L); int new_option = Old_option |    O_nonblock;    Fcntl (FD, F_SETFL, new_option); return old_option;}    void addfd (int epollfd, int fd, bool enable_et) {Epoll_event event;    EVENT.DATA.FD = FD;    Event.events = Epollin;    if (enable_et) {event.events |= epollet;    } epoll_ctl (EPOLLFD, Epoll_ctl_add, FD, &event); Setnonblocking (FD);}    void et (epoll_event* events, int number, int epollfd, int listenfd) {char buf[buffer_size]; for (int i = 0; i < number; i++) {int SOCKFD = EveNTS[I].DATA.FD;            if (sockfd = = listenfd) {struct sockaddr_in client_address;            socklen_t client_addrlength = sizeof (client_address);            int CONNFD = Accept (LISTENFD, (struct sockaddr*) &client_address, &client_addrlength);        ADDFD (EPOLLFD, CONNFD, true);            } else if (Events[i].events & Epollin) {printf ("Event Trigger once\n");                while (1) {memset (buf, ' n ', buffer_size);                int ret = recv (SOCKFD, buf, buffer_size-1, 0); if (Ret < 0) {if (errno = = Eagain) | |                    (errno = = Ewouldblock))                        {printf ("read later\n");                    Break                    } close (SOCKFD);                Break       } else if (ret = = 0) {close (SOCKFD);         } else {printf ("Get%d bytes of content:%s\n", ret, buf);        }}} else {printf ("something else happened \ n");  }}}int Main (int argc, char* argv[]) {if (argc <= 2) {printf ("Usage:%s ip_address port_number\n",        BaseName (argv[0]));    return 1;    } const char* IP = argv[1];    int port = atoi (argv[2]);    int ret = 0;    struct SOCKADDR_IN address;    Bzero (&address, sizeof (address));    address.sin_family = af_inet;    Inet_pton (Af_inet, IP, &address.sin_addr);    Address.sin_port = htons (port);    int LISTENFD = socket (pf_inet, sock_stream, 0);    ASSERT (LISTENFD >= 0);    ret = bind (LISTENFD, (struct sockaddr*) &address, sizeof (address));    ASSERT (Ret! =-1);    RET = Listen (LISTENFD, 5);    ASSERT (Ret! =-1);    Epoll_event events[Max_event_number]; int EPOLLFD = Epoll_create (5);    ASSERT (EPOLLFD! =-1);    ADDFD (EPOLLFD, LISTENFD, true);        while (1) {int ret = epoll_wait (EPOLLFD, events, Max_event_number,-1);            if (Ret < 0) {printf ("Epoll failure\n");        Break    } ET (events, ret, EPOLLFD, LISTENFD);    } close (LISTENFD); return 0;}

  

In trying a multithreaded code;

#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include < string.h> #include <fcntl.h> #include <stdlib.h> #include <sys/epoll.h> #include <pthread.h   > #define Max_event_number 1024#define buffer_size 10struct fds{int epollfd; int sockfd;};    void* worker (void* arg) {int sockfd = ((fds*) arg)->sockfd;    int EPOLLFD = ((fds*) arg)->epollfd;    printf ("Start new thread to receive data on FD:%d\n", SOCKFD);    Char buf[buffer_size];    memset (buf, ' buffer_size ');        while (1) {int ret = recv (SOCKFD, buf, buffer_size-1, 0);            if (ret = = 0) {close (SOCKFD);            printf ("Foreiner closed the connection\n");        Break } else if (Ret < 0) {if (errno = = Eagain) {//REset_oneshot (EPOLLFD, SOCKFD);                printf ("Read later\n");            Break            }} else {printf ("Get content:%s\n", buf);        Sleep (5); }} printf ("End thread receiving data on FD:%d\n", SOCKFD);} int setnonblocking (int fd) {int old_option = FCNTL (FD,F_GETFL); int new_option = Old_option | O_nonblock;fcntl (fd,f_setfl,new_option); return old_option;} void addfd (int epollfd,int fd,bool enable_et) {epoll_event event;event.data.fd = Fd;event.events = EPOLLIN;if (Enable_et) {event.events |= epollet;} Epoll_ctl (epollfd,epoll_ctl_add,fd,&event); setnonblocking (FD);} void et (epoll_event* events,int number,int epollfd,int listenfd) {char buf[buffer_size];for (int i = 0; i < number;i++) {I NT SOCKFD = events[i].data.fd;if (sockfd = = listenfd) {struct sockaddr_in client_address;socklen_t client_addrlength = sizeof (client_address); int connfd = Accept (LISTENFD, (struct sockaddr*) &client_address,&client_addrlength); ADDFD (epollfd,connfd,true);} else if (events[i].events & Epollin) {/*printf ("Event Trigger once\n"), while (1) {memset (buf, ' + ', buffer_size); int ret = recv (sockfd,buf,buffer_size-1,0); if (Ret < 0) {if (errno = = Eagain) | | (errno = = Ewouldblock)) {printf ("read later\n"); break;} Close (SOCKFD); break;} else if (ret = = 0) {close (SOCKFD);} else{printf ("Get%d bytes of content:%s \ n", Ret,buf);}}                */pthread_t thread;                FDS Fds_for_new_worker;                FDS_FOR_NEW_WORKER.EPOLLFD = EPOLLFD;                FDS_FOR_NEW_WORKER.SOCKFD = SOCKFD; Pthread_create (&thread, NULL, worker, (void*) &fds_for_new_worker);} else{printf ("Something else happened \ n");}}} int main () {int ret = 0;struct sockaddr_in Address;bzero (&address,sizeof (address)); address.sin_family = af_inet; Inet_pton (Af_inet, "127.0.0.1", &address.sin_addr); address.sin_port = htons (1134); int listenfd = socket (Af_inet, sock_stream,0), assert (LISTENFD >= 0), ret = bind (LISTENFD, (struct sockaddr*) & address,sizeof (address)); assert (ret! =-1); ret = Listen (listenfd,5); assert (ret! =-1); Epoll_event Events[max_event_ Number];int EPOLLFD = epoll_create (5); assert (EPOLLFD! = 1); ADDFD (epollfd,listenfd,true); while (1) {int ret = epoll_wait (epollfd,events,max_event_number,-1); if (Ret < 0) {printf ("Epoll failure\n"); ET (EVENTS,RET,EPOLLFD,LISTENFD);} Close (LISTENFD); return 0;}

  

In a multithreaded version, if we enter multiple times in a row, a problem occurs.

If we enter the client in Telnet several times in a row

The server will open multiple threads to accept the socket input

Shown below:

Fd:5, Sockfdget CONTENT:DFDSF
...
Start new thread to receive data on Fd:5
Fd:5, Sockfdget CONTENT:SD
...
Start new thread to receive data on Fd:5
Fd:5, Sockfdget CONTENT:SD
...
Start new thread to receive data on Fd:5
Fd:5, Sockfdget CONTENT:SD
...
Start new thread to receive data on Fd:5
Fd:5, Sockfdget CONTENT:SD
...
Start new thread to receive data on Fd:5
Fd:5, Sockfdget CONTENT:SD
...
Start new thread to receive data on Fd:5
Fd:5, Sockfdget CONTENT:SD

If multiple threads operate a socket at the same time, a variety of unexpected situations may occur

Then we need to set the socket's Epolloneshot flag.

For continuous operations, the operating system triggers the last read-write exception event on the socket.

The code is as follows:

#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include < string.h> #include <fcntl.h> #include <stdlib.h> #include <sys/epoll.h> #include <pthread.h   > #define Max_event_number 1024#define buffer_size 10struct fds{int epollfd; int sockfd;};    void Reset_oneshot (int epollfd, int fd) {epoll_event event;    EVENT.DATA.FD = FD; event.events = Epollin | Epollet |    Epolloneshot; Epoll_ctl (EPOLLFD, Epoll_ctl_mod, FD, &event);}    void* worker (void* arg) {int sockfd = ((fds*) arg)->sockfd;    int EPOLLFD = ((fds*) arg)->epollfd;    printf ("Start new thread to receive data on FD:%d\n", SOCKFD);    Char buf[buffer_size];    memset (buf, ' buffer_size ');        while (1) {int ret = recv (SOCKFD, buf, buffer_size-1, 0); if (ret = = 0) {Close (SOCKFD);            printf ("Foreiner closed the connection\n");        Break } else if (Ret < 0) {if (errno = = Eagain) {reset_oneshot (EPOLLF                D, SOCKFD);                printf ("Read later\n");            Break            }} else {printf ("Get content:%s\n", buf);        Sleep (5); }} printf ("End thread receiving data on FD:%d\n", SOCKFD);} int setnonblocking (int fd) {int old_option = FCNTL (FD,F_GETFL); int new_option = Old_option | O_nonblock;fcntl (fd,f_setfl,new_option); return old_option;} void addfd (int epollfd,int fd,bool setoneshot) {epoll_event event;event.data.fd = Fd;event.events = EPOLLIN;event.events |= epollet;if (setoneshot) event.events |= epolloneshot;epoll_ctl (epollfd,epoll_ctl_add,fd,&event); Setnonblocking (FD);} void et (epoll_event* events,int number,int epollfd,int listenfd) {char buf[buffer_size];for (int i = 0; i < number;i++) {I NT SockFD = events[i].data.fd;if (sockfd = = listenfd) {struct sockaddr_in client_address;socklen_t client_addrlength = sizeof ( client_address); int connfd = Accept (LISTENFD, (struct sockaddr*) &client_address,&client_addrlength); ADDFD ( Epollfd,connfd,true);} else if (events[i].events & Epollin) {/*printf ("Event Trigger once\n"), while (1) {memset (buf, ' + ', buffer_size); int ret = recv (sockfd,buf,buffer_size-1,0); if (Ret < 0) {if (errno = = Eagain) | | (errno = = Ewouldblock)) {printf ("read later\n"); break;} Close (SOCKFD); break;} else if (ret = = 0) {close (SOCKFD);} else{printf ("Get%d bytes of content:%s \ n", Ret,buf);}}                */pthread_t thread;                FDS Fds_for_new_worker;                FDS_FOR_NEW_WORKER.EPOLLFD = EPOLLFD;                FDS_FOR_NEW_WORKER.SOCKFD = SOCKFD; Pthread_create (&thread, NULL, worker, (void*) &fds_for_new_worker);} else{printf ("Something else happened \ n");}}} int main () {int ret = 0;struct sockaddr_in Address;bzero (&address,sizeof (address)); address.sin_family = Af_inet;inet_pton (af_inet, "127.0.0.1", &address.sin_addr); address.sin_port = htons (1134); int LISTENFD = socket (af_inet,sock_stream,0), assert (LISTENFD >= 0), ret = bind (LISTENFD, (struct sockaddr*) &address, sizeof (address)), assert (ret! =-1), ret = listen (listenfd,5); assert (ret! =-1); Epoll_event Events[max_event_number]; int EPOLLFD = epoll_create (5), assert (EPOLLFD! = 1), ADDFD (Epollfd,listenfd,false), while (1) {int ret = epoll_wait ( EPOLLFD,EVENTS,MAX_EVENT_NUMBER,-1); if (Ret < 0) {printf ("Epoll failure\n"); break;} ET (EVENTS,RET,EPOLLFD,LISTENFD);} Close (LISTENFD); return 0;}

  

Input

Trying 127.0.0.1 ...
Connected to 127.0.0.1.
Escape character is ' ^] '.
1
2
3
4
5
Sdfufghbskdjhkbaskjhbkjlsadvfblkajwsvdfbljkashdbkfjhasdfhasjkhd

Output

Start new thread to receive data on Fd:5
Get Content:1

Get Content:2
3
4

Get Content:5
Sdfufg
Get CONTENT:HBSKDJHKB
Get CONTENT:ASKJHBKJL
Get Content:sadvfblka
Get CONTENT:JWSVDFBLJ
Get CONTENT:KASHDBKFJ
Get CONTENT:HASDFHASJ
Get CONTENT:KHD
Hasj
Read later
End thread receiving data on Fd:5

Linux Network Programming IO multiplexing

Related Article

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.