Source code example of epoll edge trigger (epoll et)

Source: Internet
Author: User
Tags socket error htons

When using epoll to write network applications, especially servers. In order to obtain the optimal effect, the edge trigger (epoll ET) method is generally used. Due to edge triggering, epoll_wait returns only when the socket status changes. Therefore, the socket must be cyclically accept, read, and write until the buffer zone of the socket is empty (read, accept) or full (write. When the number of bytes returned by read is smaller than the number of bytes to be read or EAGAIN is returned, the cache zone is considered empty. As there are already many examples of how epollet handles epollin events on the network, I will only provide code to test how to handle epollout events. /*
========================================================== ==========================================
Name: epoll_test.c
Author:
Version:
Copyright: Your copyright notice
Description: epoll et example (echo) the echo server copies REPEAT_NUM20000 times of the input content, and then returns it to the client
Used to test how an epollout event is triggered.
========================================================== ==========================================
*/

# Include <stdio. h>
# Include <stdlib. h>
# Include <unistd. h>
# Include <fcntl. h>
# Include <arpa/inet. h>
# Include <netinet/in. h>
# Include <sys/epoll. h>
# Include <errno. h>
# Include <sys/types. h>
# Include <sys/socket. h>
# Include <signal. h>

# Define EPOLL_SIZE 10
# Define EVENT_ARR 20
# Define BACK_QUEUE 10
# Define PORT 18001
# Define BUF_SIZE 16
# Define REPEAT_NUM 20000
# Define OUT_BUF_SIZE 32 * REPEAT_NUM

Int g_srv_fd;

// Because it is possible that you cannot write all the content at a time, you need to save the content length and output the content to the global variable,
// Continue sending the last time after listening to the epollout event
Char g_out_buf [OUT_BUF_SIZE]; // Save the output content
Int g_out_buf_offset; // Save the output to it.
Int g_out_buf_len; // Save the length of the output content
Int g_has_write_buf; // save whether to write the output content

Void setnonblocking (int sockFd ){
Int opt;

Opt = fcntl (sockFd, F_GETFL );
If (opt <0 ){
Printf ("fcntl (F_GETFL) fail .");
Exit (-1 );
}
Opt | = O_NONBLOCK;
If (fcntl (sockFd, F_SETFL, opt) <0 ){
Printf ("fcntl (F_SETFL) fail .");
Exit (-1 );
}
}

Void handle_sig (int signum ){
Close (g_srv_fd );
Fprintf (stderr, "receiv sig int ");
Sleep (5 );
Exit (0 );
}


Int write_out_buf (int fd, char * out_buf, int buf_len, int offset)
{
Int snd_len = write (fd, out_buf + offset, buf_len-offset );
Int tmp_len;
If (snd_len = (buf_len-offset )){
Do {
Tmp_len = write (fd, out_buf + offset + snd_len, buf_len-offset-snd_len );
If (tmp_len> 0 & tmp_len <(buf_len-offset-snd_len )){
Snd_len + = tmp_len;
Break;
}
If (tmp_len =-1 ){
Break;
}
Snd_len + = tmp_len;
} While (tmp_len> 0 );
}
If (snd_len =-1 | tmp_len =-1) & errno = EAGAIN) | snd_len <buf_len-offset ){
Fprintf (stderr, "snd receiv eagin or snd_len <out_len \ r \ n ");
}
Fprintf (stderr, "snd ret: % d \ r \ n", snd_len );
Return snd_len;

}
//
Void process_write (int fd, char * in_buf, int buf_len)
{
Char * p_out_buf = g_out_buf;
Int tmp_offset;
Int I;
For (I = 0; I <REPEAT_NUM; I ++ ){
Tmp_offset + = snprintf (p_out_buf + tmp_offset, OUT_BUF_SIZE-tmp_offset, "% d: % s \ r \ n", I, in_buf );
}
G_out_buf_len = tmp_offset;
G_out_buf_offset = 0;
G_has_write_buf = 0;
G_out_buf_offset + = write_out_buf (fd, g_out_buf, g_out_buf_len, g_out_buf_offset );
Fprintf (stderr, "write_out_buf len: % d wret: % d \ r \ n", g_out_buf_len, g_out_buf_offset );
If (g_out_buf_offset <g_out_buf_len ){
G_has_write_buf = 1;
}
}


Int main (){

Int serverFd;

ServerFd = socket (AF_INET, SOCK_STREAM, 0 );
G_srv_fd = serverFd;

Setnonblocking (serverFd );
Signal (SIGPIPE, SIG_IGN );
Signal (SIGINT, handle_sig );

Int epFd = epoll_create (EPOLL_SIZE );
Struct epoll_event ev, evs [EVENT_ARR];
Ev. data. fd = serverFd;
Ev. events = EPOLLIN | EPOLLET;
Epoll_ctl (epFd, EPOLL_CTL_ADD, serverFd, & ev );

Struct sockaddr_in serverAddr;
Socklen_t serverLen = sizeof (struct sockaddr_in );
ServerAddr. sin_addr.s_addr = htonl (INADDR_ANY );
ServerAddr. sin_port = htons (PORT );
If (bind (serverFd, (struct sockaddr *) & serverAddr, serverLen )){
Printf ("bind () fail. \ n ");
Exit (-1 );
}

If (listen (serverFd, BACK_QUEUE )){
Printf ("Listen fail. \ n ");
Exit (-1 );
}

Int clientFd;
Struct sockaddr_in clientAddr;
Socklen_t clientLen;
Char buf [BUF_SIZE];

Int I = 0;
While (1 ){

Int nfds = epoll_wait (epFd, evs, EVENT_ARR,-1 );
For (I = 0; I <nfds; I ++ ){
If (evs [I]. data. fd = serverFd & (evs [I]. events & EPOLLIN )){
// The epollet needs to cyclically access the listening socket until EAGAIN is returned.
Do {
If (clientFd = accept (serverFd,
(Struct sockaddr *) & clientAddr, & clientLen) <0 ){
Printf ("accept fail. \ n ");
Break;
}
Printf ("Connect from % s: % d \ n", inet_ntoa (clientAddr. sin_addr ),
Htons (clientAddr. sin_port ));
Setnonblocking (clientFd );
Ev. data. fd = clientFd;
// Note: for efficiency, you can directly listen to EPOLLIN and EPOLLOUT events.
Ev. events = EPOLLIN | EPOLLET | EPOLLOUT;
// Ev. events = EPOLLIN;
Epoll_ctl (epFd, EPOLL_CTL_ADD, clientFd, & ev );
} While (clientFd> 0 );
} Else if (evs [I]. events & EPOLLIN ){
Fprintf (stderr, "epollin event fd: % d \ n", clientFd );
If (clientFd = evs [I]. data. fd)> 0 ){
// Epollet needs to read the socket loop until len <BUF_SIZE, or len <= 0 returns
Int len = read (clientFd, buf, BUF_SIZE );
Fprintf (stderr, "read fd: % d len: % d \ n", clientFd, len );
If (len = BUF_SIZE ){
Do {
/*
If (write (clientFd, buf, len) <0 ){
Fprintf (stderr, "write fail! \ N ");
// Break;
}
*/
Process_write (clientFd, buf, len );
If (len <BUF_SIZE ){
Fprintf (stderr, "len <bufsize % d <% d \ n", len,
BUF_SIZE );
Break;
}
Len = read (clientFd, buf, BUF_SIZE );
Fprintf (stderr, "read2 fd: % d len: % d \ n", clientFd, len );
} While (len> 0 );
If (len = 0 ){
Epoll_ctl (epFd, EPOLL_CTL_DEL, clientFd, & ev );
Close (clientFd );
Evs [I]. data. fd =-1;
Fprintf (stderr, "close fd: % d \ n", clientFd );
} Else if (len =-1 & errno! = EAGAIN ){
Fprintf (stderr, "fd: % d \ n", clientFd );
Epoll_ctl (epFd, EPOLL_CTL_DEL, clientFd, & ev );
Close (clientFd );
Evs [I]. data. fd =-1;
}
} Else if (len> 0 & len <BUF_SIZE ){
Process_write (clientFd, buf, len );
} Else if (len = 0 | (len =-1 & errno! = EAGAIN )){
Epoll_ctl (epFd, EPOLL_CTL_DEL, clientFd, & ev );
Close (clientFd );
Evs [I]. data. fd =-1;
Fprintf (stderr, "close fd: % d \ n", clientFd );
}

}
} Else if (evs [I]. events & EPOLLOUT ){
// Listening to The epollout time indicates that the sending buffer can be written, and the last write operation will continue.
ClientFd = evs [I]. data. fd;
Fprintf (stderr, "receive epoll out fd: % d \ n", clientFd );
If (g_has_write_buf ){
G_out_buf_offset + = write_out_buf (clientFd, g_out_buf, g_out_buf_len, g_out_buf_offset );
Fprintf (stderr, "write len: % d writed: % d \ n", g_out_buf_len, g_out_buf_offset );
If (g_out_buf_offset = g_out_buf_len ){
G_has_write_buf = 0;
}
}
} Else {
Printf ("other event. \ n ");
}
}
}

Return 0;
}
The following is the tested perl code epoll_test.pl )#! /Usr/bin/perl

Use IO: Socket;
My $ host = "127.0.0.1 ";
My $ port = 18001;
My $ socket = IO: Socket: INET-> new ("$ host: $ port") or die "create socket error $ @";
My $ msg_out = "1234567890 ";
Print $ socket $ msg_out;
Print "now send over, go to sleep \ n ";
Sleep (10 );
My $ msg_in;
While (1 ){
Read $ socket, $ msg_in, 10240;

Print "receiv msg $ msg_in \ n ";
}
Print "5 second gonesend another line \ n ";
# Print $ socket $ msg_out;

While (1)
{
Sleep (1 );
}
Running Effect epollin event fd: 5
Read fd: 5 len: 0
Close fd: 5
Connect from 127.0.0.1: 48552
Accept fail.
Epollin event fd:-1
Read fd: 5 len: 10
Snd receiv eagin or snd_len <out_len
Snd ret: 65536
Write_out_buf len: 408890 wret: 65536
Receive epoll out fd: 5
Snd receiv eagin or snd_len <out_len
Snd ret: 131072
Write len: 408890 writed: 196608
Receive epoll out fd: 5
Snd receiv eagin or snd_len <out_len
Snd ret: 65536
Write len: 408890 writed: 262144
Receive epoll out fd: 5
Snd receiv eagin or snd_len <out_len
Snd ret: 49152
Write len: 408890 writed: 311296
Receive epoll out fd: 5
Snd receiv eagin or snd_len <out_len
Snd ret: 49152
Write len: 408890 writed: 360448
Receive epoll out fd: 5
Snd ret: 48442
Write len: 408890 writed: 408890
Epollin event fd: 5
Read fd: 5 len: 0
Close fd: 5

This article from "My it life-linux | arm" blog, please be sure to keep this source http://herojames.blog.51cto.com/851340/303279

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.