linux epoll 程序实例,一个linux下的epoll事件模型实例

在red hat linux下(内核版本2.6以上)写了一个epoll事件模型的实例,读取客户端发送的socket请求,记录在日志文件中,暂时使用LT模式(水平模式)触发,当前采用阻塞方式进行,后续打算增加一个事件环状链表,采用多进程方式非阻塞得将事件放入事件链表中,通过子进程来处理具体事件。

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

//epoll设置为水平触发模式

#define ET 0

//定义最大事件句柄数

#define MAX_EPOLL_FD 1024

//epoll_wait收集到事件数

#define WAIT_EPOLL_NUM 20

//需要监听的事件数

#define LISTEN_EPOLL_NUM 20

//句柄错误

#define FD_ERR -1

//日志记录错误

#define LOG_ERR 0

//文件关闭错误

#define COLSE_ERR -1

//文件关闭成功

#define COLSE_SUC 0

//函数返回错误

#define RETURN_ERR 0

//函数返回成功

#define RETURN_SUC 1

//日志字符串最大长度

#define MX_LOG_STRING 1024

//最大监听数量

#define MX_LISTEN_NUM 10

//默认监听端口

#define DEFAULT_LISTEN_PORT 8801

//事件等待超时时间,单位ms

#define MX_WAIT_TIME 200

//写入或读取的缓冲区大小

#define MX_LINE 1024

//日志目录,暂时放在这里

const char *record_filename;

//运行所需全局变量

struct cycle_type{

//接收事件数组

struct epoll_event *accept_events;

//事件监听//后续数组

struct epoll_event listen_event;

//事件监听句柄

int listen_fd;

//sockte文件句柄

int socket_fd;

//socket中connetc文件句柄

int connect_fd;

//日志文件描述符

int record_fd;

//监听端口//后续数组

int listen_port;

};

struct cycle_type cycle;

//得到字符串的长度

int str_length(const char *src)

{

int strnum=0;

while(*src!= ' '){

src++;

strnum++;

}

return strnum;

}

//打开日志文件

int recordfile_open(){

//int filefd;

//根据文件名打开文件,读写模式,如果不存在直接创建,写入到文件尾部

cycle.record_fd=open(record_filename,O_WRONLY|O_CREAT|O_APPEND);

if(cycle.record_fd==FD_ERR){

printf("%s file open error!n",record_filename);

return FD_ERR;

}else{

return cycle.record_fd;

}

}

//关闭日志文件

int recordfile_close(){

//int filefd;

//关闭日志

if(close(cycle.record_fd)!=COLSE_SUC){

sprintf("%s file close error!n",record_filename);

return COLSE_ERR;

}

return COLSE_SUC;

}

//创建事件监听

int create_epoll(){

//生成用于处理accept的 epoll专用的文件描述符

//int listen_fd;

cycle.listen_fd=epoll_create(MAX_EPOLL_FD);

if(cycle.listen_fd==FD_ERR){

record_log("epoll_create error!n ",30);

return RETURN_ERR;

}

return cycle.listen_fd;

}

//记录日志,只记录日志,日志文件系统初始化时打开,退出时关闭

//先不用可选参数来做,先用库函数snprintf()来取得相关的char *值

int record_log(char * error_string,int record_size){

//char *log_str;

//int str_leng=0;

//char *record_Buf;

//record_Buf=(char *)malloc(1024);

//将程序运行相关信息赋值给变量,但是最大长度不得超过MX_LOG_STRING,否则就认为这个字符串返回的有问题(没有结束符)

//str_leng=sprintf(record_Buf,"function name: %d line num :%d ",__FUNCTION__, __LINE__);

//如果字符串长度超过限制,认为是日志记录错误

//if(str_length(log_str)>=MX_LOG_STRING){

// printf("record log error!");

// return LOG_ERR;

//}

//write(cycle.record_fd, record_Buf, str_leng);

//record_Buf=strcpy(log_str,error_string);

//如果字符串长度超过限制,认为是日志记录错误

//if(str_length(error_string)>=MX_LOG_STRING){

// printf("record log error!n");

// return LOG_ERR;

//}

//写日志文件,限定了所能写的最长字符串

write(cycle.record_fd, error_string, record_size);

//printf(error_string);

return RETURN_SUC;

}

//系统初始化

int init_system(){

int startepfd;

record_filename="log/error.log";

//memset(record_filename,0,1024);

//strcpy(record_filename,"log/error.log");

//初始化

cycle.accept_events=(struct epoll_event *)malloc(WAIT_EPOLL_NUM*sizeof(struct epoll_event));//

//cycle.listen_event=(epoll_event *)malloc(1*sizeof(epoll_event));

cycle.listen_fd=FD_ERR;

cycle.socket_fd=FD_ERR;

cycle.record_fd=FD_ERR;

cycle.listen_port=DEFAULT_LISTEN_PORT;

//打开日志文件

cycle.record_fd=recordfile_open();

if(cycle.record_fd<=0){

printf("%s file open error!n",record_filename);

return RETURN_ERR;

}

//创建事件epoll

startepfd=create_epoll();

if(startepfd<=0){

//日志函数需要修改为可变参数

record_log("create epoll error!n ",30);

return RETURN_ERR;

}

return RETURN_SUC;

}

//设置缓冲区函数,start[0]到start[str_size-1]设置为set_char,start[str_size]=' '

char *zhm_memset(char *start,const char set_char,int str_size){

int i=0;

while(i0){

err_msg1=(char *)malloc(1024);

//err_msg=(char *)malloc(1024);

sprintf(err_msg1,"listen_fd : %d n ",cycle.listen_fd);

record_log(err_msg1,20);

}else{

record_log("listen_fd error !n ",30);

continue;

}

epint=epoll_wait(cycle.listen_fd,cycle.accept_events,WAIT_EPOLL_NUM,MX_WAIT_TIME);

//sleep(1);

for(i=0;i<=epint;i++){

//事件处理,有新的连接

if(cycle.accept_events[i].data.fd==cycle.socket_fd)

{

int conn_fd;

char *err_msg,*err_msg2;//accept这个连接

printf( "CONNECT n");

record_log( "CONNECT n ",10);

if(cycle.socket_fd>0){

err_msg=NULL;

err_msg=(char *)malloc(1024);

sprintf(err_msg,"socket_fd : %d n ",cycle.socket_fd);

record_log(err_msg,20);

}else{

record_log("socket fd error !n ",30);

}

cycle.connect_fd = accept(cycle.socket_fd,( struct sockaddr *)&client_addr, &cli_len);

if(cycle.connect_fd<0){

err_msg=NULL;

err_msg=(char *)malloc(1024);

sprintf(err_msg,"errno %dn ",errno);

record_log(err_msg,20);

err_msg2=strerror(errno);

record_log(err_msg2,30);

perror( "connfd<0");

exit(1);

}

record_log("accept connect! ",20);

char *str = inet_ntoa(client_addr.sin_addr);

//char *log_str=sprintf( "accapt a connection from %sn" ,str);

//record_log(log_str);

//设置用于读操作的文件描述符

ev_tmp.data.fd=cycle.connect_fd;

//设置用于注册的读操作事件

#if ET

ev_tmp.events=EPOLLIN|EPOLLET;

#else

ev_tmp.events=EPOLLIN;

#endif

//注册ev_tmp

epoll_ctl(cycle.listen_fd,EPOLL_CTL_ADD,cycle.connect_fd,&ev_tmp);

}else if(cycle.accept_events[i].events&EPOLLIN)//接收到数据,读socket

{

int sock_fd;

char *read_log;

char *line;

char *err_msg,*err_msg2;

int n;

printf( "EPOLLINn");

record_log( "EPOLLINn ",10);

line=(char *)malloc(1024*sizeof(char));

//line=(char *)zhm_memset(line,0,1024);

//line=(char *)memset((void *)linetmp,0,1024*sizeof(char));

//if ((cycle.socket_fd = cycle.accept_events[i].data.fd) < 0)

// continue;

if(cycle.socket_fd>0){

//err_msg=(char *)malloc(1024*sizeof(char));

//sprintf(err_msg,"socket_fd : %d n",cycle.socket_fd);

//record_log(err_msg);

record_log("socket fd right !n ",20);

}else{

record_log("socket fd error !n ",20);

}

printf("read begin!n");

if ((n = read(cycle.connect_fd, line, MX_LINE))<0){

printf("read error!n");

if(errno>0){

//sprintf(err_msg, "errno %dn",errno);

//record_log(err_msg);

err_msg2=strerror(errno);

record_log(err_msg2,30);

record_log("n ",2);

}

if (errno == ECONNRESET) {

close(cycle.socket_fd);

cycle.accept_events[i].data.fd = -1;

} else{

record_log( "read error!n ",10);

}

}else if (n == 0){

printf("read empty!n");

close(cycle.socket_fd);

cycle.accept_events[i].data.fd = -1;

}else{

printf("read fininsh! n");

record_log("read fininsh! n ",20);

line[n] = ' ';

err_msg=(char *)malloc(1024*sizeof(char));

sprintf(err_msg,"read %sn ",line);

record_log(err_msg,n);

//record_log(read_log);

}

//设置用于写操作的文件描述符

ev_tmp.data.fd=cycle.socket_fd;

//设置用于注册的写操作事件

#if ET

ev_tmp.events=EPOLLOUT|EPOLLET;

#else

ev_tmp.events=EPOLLOUT;

#endif

//修改sockfd 上要处理的事件为 EPOLLOUT,设置下一个循环为输出事件

epoll_ctl(cycle.listen_fd,EPOLL_CTL_MOD,cycle.socket_fd,&ev_tmp);

}else if(cycle.accept_events[i].events&EPOLLOUT)//有数据待发送,写socket

{

char *line;

//int sock_fd;

record_log( "EPOLLOUTn ",10);

//int n=20;

//没有东西发送

memset(line,0,1024);

//memset(line,' ',20);

cycle.socket_fd = cycle.accept_events[i].data.fd;

write(cycle.socket_fd, line, MX_LINE);

//设置用于写操作的文件描述符

ev_tmp.data.fd=cycle.connect_fd;

//设置用于注册的写操作事件

#if ET

ev_tmp.events=EPOLLIN|EPOLLET;

#else

ev_tmp.events=EPOLLIN;

#endif

//修改sockfd 上要处理的事件为 EPOLLOUT,设置下一个循环为输出事件

epoll_ctl(cycle.listen_fd,EPOLL_CTL_MOD,cycle.connect_fd,&ev_tmp);

}

sleep(1);

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值