linux epoll是只针对网络编程吗
展开全部
对于改进poll的epoll来说:支持一个进程打开大数目的socket描述符,也就是说与本机的内存是有关系的!( 一般服务器的都是很大的! )
下面是我的小PC机上的显示:
pt@ubuntu:~$ cat /proc/sys/fs/file-max
391658
达到了391658个,那么对于服务器而言,显然,嘿嘿嘿~~~
epoll的基础知识吧大家在网上到处都能找到,不就是epoll_creat 、epoll_ctl、epoll_wait 3函数!大家自己搜去,我也是在学习。。。
此处主要是贴上自己的测试的一些垃圾代码,与大家共勉!呵呵呵~
哦,忘了要注意一下:
epoll_ctl epoll的事件注册函数,其events参数可以是以下宏的集合:
EPOLLIN: 表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
EPOLLOUT: 表示对应的文件描述符可以写;
EPOLLPRI: 表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR: 表示对应的文件描述符发生错误;写已关闭socket pipe broken
EPOLLHUP: 表示对应的文件描述符被挂断;譬如收到RST包。在注册事件的时候这个事件是默认添加。
EPOLLRDHUP: 表示对应的文件描述符对端socket关闭事件,主要应用于ET模式下。
在水平触发模式下,如果对端socket关闭,则会一直触发epollin事件,驱动去处理client socket。
在边沿触发模式下,如果client首先发送协议然后shutdown写端。则会触发epollin事件。但是如果处理程序只进行一次recv操作时,根据recv收取到得数据长度来判读后边是
否还有需要处理的协议时,将丢失客户端关闭事件。
EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里
server端:
[cpp] view plaincopy
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h> /* socket类定义需要*/
#include <sys/epoll.h> /* epoll头文件 */
#include <fcntl.h> /* nonblocking需要 */
#include <sys/resource.h> /* 设置最大的连接数需要setrlimit */
#define MAXEPOLL 10000 /* 对于服务器来说,这个值可以很大的! */
#define MAXLINE 1024
#define PORT 6000
#define MAXBACK 1000
//!> 设置非阻塞
//!>
int setnonblocking( int fd )
{
if( fcntl( fd, F_SETFL, fcntl( fd, F_GETFD, 0 )|O_NONBLOCK ) == -1 )
{
printf("Set blocking error : %d\n", errno);
return -1;
}
return 0;
}
int main( int argc, char ** argv )
{
int listen_fd;
int conn_fd;
int epoll_fd;
int nread;
int cur_fds; //!> 当前已经存在的数量
int wait_fds; //!> epoll_wait 的返回值
int i;
struct sockaddr_in servaddr;
struct sockaddr_in cliaddr;
struct epoll_event ev;
struct epoll_event evs[MAXEPOLL];
struct rlimit rlt; //!> 设置连接数所需
char buf[MAXLINE];
socklen_t len = sizeof( struct sockaddr_in );
//!> 设置每个进程允许打开的最大文件数
//!> 每个主机是不一样的哦,一般服务器应该很大吧!
//!>
rlt.rlim_max = rlt.rlim_cur = MAXEPOLL;
if( setrlimit( RLIMIT_NOFILE, &rlt ) == -1 )
{
printf("Setrlimit Error : %d\n", errno);
exit( EXIT_FAILURE );
}
//!> server 套接口
//!>
bzero( &servaddr, sizeof( servaddr ) );
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl( INADDR_ANY );
servaddr.sin_port = htons( PORT );
//!> 建立套接字
if( ( listen_fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
{
printf("Socket Error...\n" , errno );
exit( EXIT_FAILURE );
}
//!> 设置非阻塞模式
//!>
if( setnonblocking( listen_fd ) == -1 )
{
printf("Setnonblocking Error : %d\n", errno);
exit( EXIT_FAILURE );
}
//!> 绑定
//!>
if( bind( listen_fd, ( struct sockaddr *)&servaddr, sizeof( struct sockaddr ) ) == -1 )
{
printf("Bind Error : %d\n", errno);
exit( EXIT_FAILURE );
}
//!> 监听
//!>
if( listen( listen_fd, MAXBACK ) == -1 )
{
printf("Listen Error : %d\n", errno);
exit( EXIT_FAILURE );
}
//!> 创建epoll
//!>
epoll_fd = epoll_create( MAXEPOLL ); //!> create
ev.events = EPOLLIN | EPOLLET; //!> accept Read!
ev.data.fd = listen_fd; //!> 将listen_fd 加入
if( epoll_ctl( epoll_fd, EPOLL_CTL_ADD, listen_fd, &ev ) < 0 )
{
printf("Epoll Error : %d\n", errno);
exit( EXIT_FAILURE );
}
cur_fds = 1;
while( 1 )
{
if( ( wait_fds = epoll_wait( epoll_fd, evs, cur_fds, -1 ) ) == -1 )
{
printf( "Epoll Wait Error : %d\n", errno );
exit( EXIT_FAILURE );
}
for( i = 0; i < wait_fds; i++ )
{
if( evs[i].data.fd == listen_fd && cur_fds < MAXEPOLL )
//!> if是监听端口有事
{
if( ( conn_fd = accept( listen_fd, (struct sockaddr *)&cliaddr, &len ) ) == -1 )
{
printf("Accept Error : %d\n", errno);
exit( EXIT_FAILURE );
}
printf( "Server get from client !\n"/*, inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port */);
ev.events = EPOLLIN | EPOLLET; //!> accept Read!
ev.data.fd = conn_fd; //!> 将conn_fd 加入
if( epoll_ctl( epoll_fd, EPOLL_CTL_ADD, conn_fd, &ev ) < 0 )
{
printf("Epoll Error : %d\n", errno);
exit( EXIT_FAILURE );
}
++cur_fds;
continue;
}
//!> 下面处理数据
//!>
nread = read( evs[i].data.fd, buf, sizeof( buf ) );
if( nread <= 0 ) //!> 结束后者出错
{
close( evs[i].data.fd );
epoll_ctl( epoll_fd, EPOLL_CTL_DEL, evs[i].data.fd, &ev ); //!> 删除计入的fd
--cur_fds; //!> 减少一个呗!
continue;
}
write( evs[i].data.fd, buf, nread ); //!> 回写
}
}
下面是我的小PC机上的显示:
pt@ubuntu:~$ cat /proc/sys/fs/file-max
391658
达到了391658个,那么对于服务器而言,显然,嘿嘿嘿~~~
epoll的基础知识吧大家在网上到处都能找到,不就是epoll_creat 、epoll_ctl、epoll_wait 3函数!大家自己搜去,我也是在学习。。。
此处主要是贴上自己的测试的一些垃圾代码,与大家共勉!呵呵呵~
哦,忘了要注意一下:
epoll_ctl epoll的事件注册函数,其events参数可以是以下宏的集合:
EPOLLIN: 表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
EPOLLOUT: 表示对应的文件描述符可以写;
EPOLLPRI: 表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR: 表示对应的文件描述符发生错误;写已关闭socket pipe broken
EPOLLHUP: 表示对应的文件描述符被挂断;譬如收到RST包。在注册事件的时候这个事件是默认添加。
EPOLLRDHUP: 表示对应的文件描述符对端socket关闭事件,主要应用于ET模式下。
在水平触发模式下,如果对端socket关闭,则会一直触发epollin事件,驱动去处理client socket。
在边沿触发模式下,如果client首先发送协议然后shutdown写端。则会触发epollin事件。但是如果处理程序只进行一次recv操作时,根据recv收取到得数据长度来判读后边是
否还有需要处理的协议时,将丢失客户端关闭事件。
EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里
server端:
[cpp] view plaincopy
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h> /* socket类定义需要*/
#include <sys/epoll.h> /* epoll头文件 */
#include <fcntl.h> /* nonblocking需要 */
#include <sys/resource.h> /* 设置最大的连接数需要setrlimit */
#define MAXEPOLL 10000 /* 对于服务器来说,这个值可以很大的! */
#define MAXLINE 1024
#define PORT 6000
#define MAXBACK 1000
//!> 设置非阻塞
//!>
int setnonblocking( int fd )
{
if( fcntl( fd, F_SETFL, fcntl( fd, F_GETFD, 0 )|O_NONBLOCK ) == -1 )
{
printf("Set blocking error : %d\n", errno);
return -1;
}
return 0;
}
int main( int argc, char ** argv )
{
int listen_fd;
int conn_fd;
int epoll_fd;
int nread;
int cur_fds; //!> 当前已经存在的数量
int wait_fds; //!> epoll_wait 的返回值
int i;
struct sockaddr_in servaddr;
struct sockaddr_in cliaddr;
struct epoll_event ev;
struct epoll_event evs[MAXEPOLL];
struct rlimit rlt; //!> 设置连接数所需
char buf[MAXLINE];
socklen_t len = sizeof( struct sockaddr_in );
//!> 设置每个进程允许打开的最大文件数
//!> 每个主机是不一样的哦,一般服务器应该很大吧!
//!>
rlt.rlim_max = rlt.rlim_cur = MAXEPOLL;
if( setrlimit( RLIMIT_NOFILE, &rlt ) == -1 )
{
printf("Setrlimit Error : %d\n", errno);
exit( EXIT_FAILURE );
}
//!> server 套接口
//!>
bzero( &servaddr, sizeof( servaddr ) );
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl( INADDR_ANY );
servaddr.sin_port = htons( PORT );
//!> 建立套接字
if( ( listen_fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
{
printf("Socket Error...\n" , errno );
exit( EXIT_FAILURE );
}
//!> 设置非阻塞模式
//!>
if( setnonblocking( listen_fd ) == -1 )
{
printf("Setnonblocking Error : %d\n", errno);
exit( EXIT_FAILURE );
}
//!> 绑定
//!>
if( bind( listen_fd, ( struct sockaddr *)&servaddr, sizeof( struct sockaddr ) ) == -1 )
{
printf("Bind Error : %d\n", errno);
exit( EXIT_FAILURE );
}
//!> 监听
//!>
if( listen( listen_fd, MAXBACK ) == -1 )
{
printf("Listen Error : %d\n", errno);
exit( EXIT_FAILURE );
}
//!> 创建epoll
//!>
epoll_fd = epoll_create( MAXEPOLL ); //!> create
ev.events = EPOLLIN | EPOLLET; //!> accept Read!
ev.data.fd = listen_fd; //!> 将listen_fd 加入
if( epoll_ctl( epoll_fd, EPOLL_CTL_ADD, listen_fd, &ev ) < 0 )
{
printf("Epoll Error : %d\n", errno);
exit( EXIT_FAILURE );
}
cur_fds = 1;
while( 1 )
{
if( ( wait_fds = epoll_wait( epoll_fd, evs, cur_fds, -1 ) ) == -1 )
{
printf( "Epoll Wait Error : %d\n", errno );
exit( EXIT_FAILURE );
}
for( i = 0; i < wait_fds; i++ )
{
if( evs[i].data.fd == listen_fd && cur_fds < MAXEPOLL )
//!> if是监听端口有事
{
if( ( conn_fd = accept( listen_fd, (struct sockaddr *)&cliaddr, &len ) ) == -1 )
{
printf("Accept Error : %d\n", errno);
exit( EXIT_FAILURE );
}
printf( "Server get from client !\n"/*, inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port */);
ev.events = EPOLLIN | EPOLLET; //!> accept Read!
ev.data.fd = conn_fd; //!> 将conn_fd 加入
if( epoll_ctl( epoll_fd, EPOLL_CTL_ADD, conn_fd, &ev ) < 0 )
{
printf("Epoll Error : %d\n", errno);
exit( EXIT_FAILURE );
}
++cur_fds;
continue;
}
//!> 下面处理数据
//!>
nread = read( evs[i].data.fd, buf, sizeof( buf ) );
if( nread <= 0 ) //!> 结束后者出错
{
close( evs[i].data.fd );
epoll_ctl( epoll_fd, EPOLL_CTL_DEL, evs[i].data.fd, &ev ); //!> 删除计入的fd
--cur_fds; //!> 减少一个呗!
continue;
}
write( evs[i].data.fd, buf, nread ); //!> 回写
}
}
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询