epoll边缘触发(epoll et) 源代码例子

 在利用epoll编写网络应用程序,特别是服务器的时候。为了得到最优的效果,一般采用边缘触发(epoll ET)的方式。由于边缘触发,epoll_wait只有在套接字状态发生变化的时候才会返回。所以要对套接字(socket)进行循环accept,read,write;直到套接字的缓冲区空(read,accept)或者填满(write)为止。当read返回的字节数小于要读的字节数,或者返回EAGAIN的时候,认为缓存区为空了。由于网络上已经有很多epollet如何处理epollin事件的例子,所以下面是本人只提供测试如何处理epollout事件的代码。

 

/* ============================================================================ Name : epoll_test.c Author : Version : Copyright : Your copyright notice Description : epoll et example(echo) 此echo服务器对输入的内容复制了REPEAT_NUM(20000次),然后返回给客户端 用于测试epollout事件如何触发。 ============================================================================ */ #include #include #include #include #include #include #include #include #include #include #include #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; //由于有可能不能一次write所有的内容,所以需要全局变量保存内容的长度,内容输出到那里, //在监听到epollout事件后继续上一次的发送 char g_out_buf[OUT_BUF_SIZE];//保存输出的内容 int g_out_buf_offset; //保存输出到那里 int g_out_buf_len; //保存输出内容的长度 int g_has_write_buf; //保存是否要写输出内容 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_len0); } else if (evs[i].events & EPOLLIN) { fprintf(stderr, "epollin event fd:%d/n", clientFd); if ((clientFd = evs[i].data.fd) > 0) { //epollet需要对套接字循环的读,直到len < BUF_SIZE,或者len<=0返回 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

 

下面是测试的perl代码(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); }

 

运行效果
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

你可能感兴趣的:(epoll)