自己抽空写的一个epoll事件处理框架

工作之余,重温了一下epoll事件处理模型,写了一个多进程非阻塞的epoll事件异步处理框架,设置epoll为边缘触发,事件放在一个循环链表中。不过还不太完善,缺少进程之间的信号和IPC通信。

首先是makefile文件,epollarray.h是定义的epoll事件循环链表头文件,helloepoll.h是事件处理头文件,两个.c是处理内容

helloepoll:helloepoll.o epollarray.o
    cc -o helloepoll helloepoll.o epollarray.o

helloepoll.o:helloepoll.c epollarray.h helloepoll.h
    cc -c -g -I/epoll helloepoll.c
epollarray.o:epollarray.c epollarray.h helloepoll.h
    cc -c -g -I/epoll epollarray.c

.PHONY:clean
clean:
    rm helloepoll.o epollarray.o

epollarray.h如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <sys/epoll.h>

#define BUF_SIZE 1024

/*
设置一个环形链表来作为存放事件队列的机构
在系统初始化时申请用循环申请所有内存,并把最后一个的next_event值设置为第一个元素的地址
读取一个事件时,读取完成后,将cur_event值为无效初始值,读取记录往后移动一位
添加一个事件(初始事件不算)时,设置当前写入元素的cur_event值,并向后移动一位,
判断当前写入和读取的元素是不是同一个(地址相同),如果相同,那么链表已满,返回错误
*/

struct epoll_current{
        //连接事件的读取缓冲区
    char read_buf[BUF_SIZE];
    //连接事件的写入缓冲区
    char write_buf[BUF_SIZE];
    //连接描述符
    int connect_fd;
    struct epoll_event cur_event;
    struct epoll_current *next_event;
};

struct epoll_array{
    //事件链表的尺寸
    int array_size;
    //链表当前读取的一个
    struct epoll_current *cur_read_event;
    //链表中当前写入的位置
    struct epoll_current *cur_write_event;

    struct epoll_current **events;

    //判断链表是否为空 1为空,0不为空,为空时不可再读取事件
    int is_empty;
    //判断链表是否为满 1为满,0不为满,为满时不可再写入事件
    int is_full;
};

//在系统初始化时申请用循环申请所有内存,并把最后一个的next_event值设置为第一个元素的地址
void init_array();

//读取一个事件时,读取完成后,将cur_event值为无效初始值,读取记录往后移动一位
int get_event(struct epoll_array *epoll_cycle,struct epoll_current *epoll_tmp);

//添加一个事件(初始事件不算)时,设置当前写入元素的cur_event值,并向后移动一位,
//判断当前写入和读取的元素是不是同一个(地址相同),如果相同,那么链表已满,返回错误
void set_event(struct epoll_array *epoll_cycle,struct epoll_current *epoll_tmp);

helloepoll.h如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <sys/epoll.h>

//epoll设置为边缘触发模式
#define ET 1
//定义最大事件句柄数
#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 80
//事件等待超时时间,单位ms
#define MX_WAIT_TIME 200
//写入或读取的缓冲区大小
#define MX_LINE 1024
//子进程数量
#define WORK_PROCESS_NUM 10

//日志目录,暂时放在这里
const char *record_filename;


//运行所需全局变量,考虑是否有必要用锁,或者使用数组之类的增加并发量
struct cycle_type{
    //接收事件数组
    struct epoll_event *accept_events;
    //事件监听//后续数组
    struct epoll_event listen_event;
    //事件链表
    struct epoll_array *epoll_cycle;

    //事件监听句柄
    int epl_lis_fd;
    //sockte文件句柄
    int socket_fd;
    //socket中connetc文件句柄
    //int connect_fd;
    //日志文件描述符
    int record_fd;
    //监听端口//后续数组
    int listen_port;
};
struct cycle_type cycle;

epollarray.c是处理事件链表的函数,定义了初始化,存放事件,取事件三个函数

#include "epollarray.h"
#include "helloepoll.h"


//链表容量
#define EPOLL_ARRAY_MX 100
//链表为空,没有任何事件
#define ARRAY_EMPTY 2
//设置读写缓冲区
#define BUF_SIZE 1024
/*
设置一个环形链表来作为存放事件队列的机构
在系统初始化时申请用循环申请所有内存,并把最后一个的next_event值设置为第一个元素的地址
读取一个事件时,读取完成后,将cur_event值为无效初始值,读取记录往后移动一位
添加一个事件(初始事件不算)时,设置当前写入元素的cur_event值,并向后移动一位,
判断当前写入和读取的元素是不是同一个(地址相同),如果相同,那么链表已满,返回错误
*/


//在系统初始化时申请用循环申请所有内存,并把最后一个的next_event值设置为第一个元素的地址
void init_array(){
    int i;

    //cycle.epoll_cycle=NULL;
    cycle.epoll_cycle=(struct epoll_array *)malloc(sizeof(struct epoll_array));
    //cycle.epoll_cycle->events=NULL;

    struct epoll_current *epoll_init_top,*epoll_init_tmp,*epoll_init_last;
    epoll_init_top=(struct epoll_current *)malloc(sizeof(struct epoll_current));
    epoll_init_top->next_event=NULL;
    epoll_init_tmp=epoll_init_top;
    //设置环形链表,将最后一个的next设置第一个的地址
    for(i=0;i<EPOLL_ARRAY_MX;i++){
        struct epoll_current *epoll_init;
        //申请空间,注意用完是否需要释放,注意判断内存是否申请成功
        epoll_init=(struct epoll_current *)malloc(sizeof(struct epoll_current));
        //清空缓冲区
        memset(epoll_init->read_buf,0,BUF_SIZE);
        memset(epoll_init->write_buf,0,BUF_SIZE);
        //将每个的next_event设置为下一个的地址
        //epoll_init->next_event=epoll_init_top->next_event;
        //epoll_init_top->next_event=epoll_init;
        //epoll_init_top=epoll_init;
        epoll_init_top->next_event=epoll_init;
        epoll_init->next_event=NULL;
        epoll_init_top=epoll_init_top->next_event;

        epoll_init_last=epoll_init;
        //cycle.epoll_cycle->events[i]=epoll_init;
    }
    //将最后一个的next设置第一个的地址
    epoll_init_last->next_event=epoll_init_tmp;

    //将链表读写起始点设为第一个节点地址
    cycle.epoll_cycle->cur_read_event=epoll_init_tmp;
    cycle.epoll_cycle->cur_write_event=epoll_init_tmp;

    cycle.epoll_cycle->is_empty=1;
    cycle.epoll_cycle->is_full=0;
    //return RETURN_SUC;
}

//读取一个事件时,读取完成后,将cur_event值为无效初始值,读取记录往后移动一位
//注意加锁
int get_event(struct epoll_array *epoll_cycle,struct epoll_current *epoll_tmp){

    //判断事件链表是否还在为空状态
    if(epoll_cycle->cur_read_event->cur_event.data.fd==0){
        printf("the event array is empty!");
        epoll_cycle->is_empty=1;
        return ARRAY_EMPTY;
    }

    if(epoll_cycle->cur_read_event->next_event==epoll_cycle->cur_write_event){
        //判断事件链表马上就进入为空状态,设置变量,阻止读取事件进行
        epoll_cycle->is_empty=1;
    }else{
        //判断事件链表还没进入为空状态
        epoll_cycle->is_empty=0;
    }

    //读取一个事件
    epoll_tmp->cur_event.data.fd=epoll_cycle->cur_read_event->cur_event.data.fd;
    epoll_tmp->cur_event.events=epoll_cycle->cur_read_event->cur_event.events;
    memcpy(epoll_tmp->read_buf,epoll_cycle->cur_read_event->read_buf,BUF_SIZE);
    memcpy(epoll_tmp->write_buf,epoll_cycle->cur_read_event->write_buf,BUF_SIZE);

    //将事件所在的文件句柄置为空
    epoll_cycle->cur_read_event->cur_event.data.fd=0;
    //清空读缓冲区
    memset(epoll_cycle->cur_read_event->read_buf,0,BUF_SIZE);
    memset(epoll_cycle->cur_read_event->write_buf,0,BUF_SIZE);
    //读取记录往后移动一位
    epoll_cycle->cur_read_event=epoll_cycle->cur_read_event->next_event;

    //读取了一个事件,链表状态为不满
    epoll_cycle->is_full=0;

}

//添加一个事件(初始事件不算)时,设置当前写入元素的cur_event值,并向后移动一位,
//判断当前写入和读取的元素是不是同一个(地址相同),如果相同,那么链表已满,返回错误
//注意加锁
void set_event(struct epoll_array *epoll_cycle,struct epoll_current *epoll_tmp){
    //将事件所在的文件句柄和events设置需要添加的events
    epoll_cycle->cur_write_event->cur_event.data.fd=epoll_tmp->cur_event.data.fd;
    epoll_cycle->cur_write_event->cur_event.events=epoll_tmp->cur_event.events;
    memcpy(epoll_cycle->cur_write_event->read_buf,epoll_tmp->read_buf,BUF_SIZE);
    memcpy(epoll_cycle->cur_write_event->write_buf,epoll_tmp->write_buf,BUF_SIZE);
    //清空写缓冲区
    //epoll_cycle->cur_read_event->cur_event.write_buf=memset(epoll_cycle->cur_read_event->cur_event.write_buf,0,BUF_SIZE);
    //写入记录往后移动一位
    epoll_cycle->cur_write_event=epoll_cycle->cur_write_event->next_event;

    if(epoll_cycle->cur_write_event->next_event==epoll_cycle->cur_read_event){
        //判断事件链表马上就进入满状态,设置变量,阻止写入事件进行
        epoll_cycle->is_full=1;
    }else{
        epoll_cycle->is_full=0;
    }
    //写入了一个事件,链表状态为不空
    epoll_cycle->is_empty=0;
}

helloepoll.c是整个框架的主体,主要负责创建父子进程,处理,记录日志等。

#include "helloepoll.h"
#include "epollarray.h"

int set_non_block(int sock_fd)
{
    int opts;
    opts=fcntl(sock_fd,F_GETFL);
    if(opts<0)
    {
       return FD_ERR;
    }
    opts = opts|O_NONBLOCK;
    if(fcntl(sock_fd,F_SETFL,opts)<0)
    {
      return FD_ERR;
    }
}

//正整数转化为char*
void zhm_itoa(int int_tmp,char *char_tmp){
    char tmp[10];
    int i=0,j=0;
    int int_sh=int_tmp,int_yu=0;
    while(int_sh>=10){
        int_yu=int_sh%10;
        //将int 型从小到大每位与48得到对应字符
        tmp[i]=int_yu&0x30;
        //每位除10
        int_sh=int_sh/10;
        i++;
    }
    tmp[i]=int_yu&0x30;
    while(j<=i){
        *(char_tmp+j)=tmp[i-j];
        j++;
    }
}

//得到字符串的长度
int str_length(const char *src)
{
    int strnum=0;
    while(*src!= '\0'){
        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;
}


//记录日志,只记录日志,日志文件系统初始化时打开,退出时关闭
//做成可变参数的函数,但是只判断s,d,c(字符串,整数,字符)三种
int record_log(char last[],...){
    //char *buf;
    char buf[30];
    //last未空
    char    *p;
    int i=0;
    int   tmp_int;
    char *tmp_str;
    char tmp_char;

    struct epoll_current *epoll_tmp;

    epoll_tmp=(struct epoll_current *)malloc(sizeof(struct epoll_current));
    //buf=(char *)malloc(MX_LINE*sizeof(char));

    va_list args;
  va_start(args,last);
    //循环
     while(*last&&i<MX_LINE){
            //判断是否遇到%
            if(*last=='%'){
                last++;
                //如果遇到,判断下一位是d还是s还是c
                switch(*last){
                        //如果是s 将字符串加到buf中再继续
                    case 's':
                        p = va_arg(args,char *);
                        while(*p){
                            //*buf=*p;
                            buf[i]=*p;
                            //buf++;
                            i++;
                            p++;
                        }
                        //如果是d 将int转为字符串加到buf中再继续
                    case 'd':
                        tmp_int= va_arg(args,int);
                        zhm_itoa(tmp_int,tmp_str);
                        while(*tmp_str){
                            //*buf=*tmp_str;
                            buf[i]=*tmp_str;
                            i++;
                            //buf++;
                            tmp_str++;
                        }
                            //如果是c 将字符加入到buf中再继续
                    case 'c':
                        tmp_char=va_arg(args,size_t);
                        //tmp_char=(*(char *)((args+=_INTSIZEOF(char))-_INTSIZEOF(char)));
                        //*buf=tmp_char;
                        buf[i]=tmp_char;
                        i++;
                        //buf++;
                    default:
                        continue;
                }
            }else{
                //如果没有,将last赋给buf
                //*buf=*last;
                buf[i]=*last;
                i++;
                //buf++;
                last++;
            }
     }
    va_end(args);
    *buf='\0';


    //将写日志动作放入事件队列中
    epoll_tmp->cur_event.data.fd=cycle.record_fd;
    //epoll_tmp->write_buf=NULL;
    memcpy(epoll_tmp->write_buf,(void *)buf,i);
    epoll_tmp->cur_event.events=EPOLLOUT;
    set_event(cycle.epoll_cycle,epoll_tmp);
    //write(cycle.record_fd, buf, i);

    //free(buf);
    //buf=NULL;
    free(epoll_tmp);
    epoll_tmp=NULL;
    //printf(error_string);
    return RETURN_SUC;
}

//创建事件监听
int create_epoll(){
    //生成用于处理accept的 epoll专用的文件描述符
    //int listen_fd;
    cycle.epl_lis_fd=epoll_create(MAX_EPOLL_FD);

    if(cycle.epl_lis_fd==FD_ERR){

        char char_tmp[]="epoll_create error!\n\0";
        record_log(char_tmp);
        return RETURN_ERR;
    }
    return cycle.epl_lis_fd;
}



//系统初始化
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.epl_lis_fd=FD_ERR;
    cycle.socket_fd=FD_ERR;
    cycle.record_fd=FD_ERR;
    cycle.listen_port=DEFAULT_LISTEN_PORT;

    //初始化事件链表
    init_array();

    //打开日志文件
    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\0");
        return RETURN_ERR;
    }

    //为这个写日志注册一个读事件
    struct epoll_event ev_tmp;
    //设置用于读操作的文件描述符
    ev_tmp.data.fd=cycle.record_fd;
    //设置用于注册的读操作事件
    #if ET
    ev_tmp.events=EPOLLIN|EPOLLET;
    #else
    ev_tmp.events=EPOLLIN;
    #endif
    //注册ev_tmp
    epoll_ctl(cycle.epl_lis_fd,EPOLL_CTL_ADD,ev_tmp.data.fd,&ev_tmp);
    return RETURN_SUC;
}
//设置缓冲区函数,start[0]到start[str_size-1]设置为set_char,start[str_size]='\0'
char *zhm_memset(char *start,const char set_char,int str_size){
    int i=0;
    while(i<str_size){
        start[i]=set_char;
    }
    start[str_size]='\0';
    return start;
}

//创建socket并且设置sockte模式,并开始监听,失败返回0,成功返回
int listen_socket(){
    int epollfd;
    int res;
    char *err_msg;
    struct sockaddr_in serveraddr;

    cycle.socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(cycle.socket_fd<=0){ 
        //sprintf(err_msg,"socket fd:%d\n\0",cycle.socket_fd); 
        record_log("socket fd:%d\n\0",cycle.socket_fd);
        return RETURN_ERR;
    };
    //把socket 设置为非阻塞方式
#if ET
    //当使用边缘触发时,因为只发送一遍,必须设置为非阻塞模式
    set_non_block(cycle.socket_fd);
#endif
    //设置与要处理的事件相关的文件描述符
    cycle.listen_event.data.fd=cycle.socket_fd;
    //设置要处理的事件类型
#if ET
    cycle.listen_event.events=EPOLLIN|EPOLLET;
#else
    cycle.listen_event.events=EPOLLIN;
#endif
    create_epoll();
  epoll_ctl(cycle.epl_lis_fd,EPOLL_CTL_ADD,cycle.socket_fd,&(cycle.listen_event));
    //memset(&address, 0, sizeof(address));
    serveraddr.sin_family = AF_INET ;
    serveraddr.sin_port =htons(cycle.listen_port);
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); //inet_addr("127.0.0.1");
    res = bind(cycle.socket_fd, (struct sockaddr *) &serveraddr, sizeof( serveraddr ) );
    if(res){ 
        printf( "port is used , not to repeat bind\n" ); 
        return RETURN_ERR;
    };
    res = listen(cycle.socket_fd,MX_LISTEN_NUM);
    if(res) { 
        printf( "listen port is error ;\n" ); 
        return RETURN_ERR;
    };
    return RETURN_SUC ;
}

//接收客户端连接
int accept_conn(struct epoll_current *epoll_tmp){
    //int conn_fd;
    char *err_msg;//accept这个连接
    record_log( "CONNECT \n\0");
    socklen_t cli_len;
    struct sockaddr_in client_addr;
    cli_len = sizeof(struct sockaddr);
    //判断socket句柄是否可用
    if(cycle.socket_fd>0){
        err_msg=NULL;
        err_msg=(char *)malloc(1024);
        sprintf(err_msg,"socket_fd : %d \n\0",cycle.socket_fd);
        record_log(err_msg);
        free(err_msg);
        err_msg=NULL;
    }else{
        record_log("socket fd error !\n\0");
        return RETURN_ERR;
    }
    //accept连接
    epoll_tmp->cur_event.data.fd = accept(cycle.socket_fd,( struct sockaddr *)&client_addr, &cli_len);
    if(epoll_tmp->cur_event.data.fd <0){
        err_msg=NULL;
        err_msg=(char *)malloc(1024);
        sprintf(err_msg,"errno %d\n\0",errno);
        record_log(err_msg);
        err_msg=NULL;
        err_msg=strerror(errno);
        record_log(err_msg);
        free(err_msg);
        err_msg=NULL;
        return RETURN_ERR;
    }
    record_log("accept connect!\0");
    return RETURN_SUC;
}

//connect事件后读取连接中的数据
int conn_read(struct epoll_current *epoll_tmp){
    int sock_fd;
    char *read_log;
    //char *line;
    char *err_msg;
    int n;
    record_log( "EPOLLIN\n\0");

    //line=(char *)malloc(1024*sizeof(char));
    if(cycle.socket_fd>0){
        record_log("socket fd right !\n\0");
    }else{
        record_log("socket fd error !\n\0");
        return RETURN_ERR;
    }

    if ((n = read(epoll_tmp->cur_event.data.fd , epoll_tmp->read_buf, MX_LINE))<0){

        printf("read error!\n");
        if(errno>0){
            //sprintf(err_msg, "errno %d\n",errno);
            //record_log(err_msg);
            err_msg=NULL;
            err_msg=strerror(errno);
            record_log(err_msg);
            record_log("\n\0");
        }
        if (errno == ECONNRESET) {
            close(cycle.socket_fd);
            //cycle.accept_events[i].data.fd = -1;
        } else{
            record_log( "read error!\n\0");
        }
        return RETURN_ERR;
    }else if (n == 0){
        printf("read empty!\n");
        close(cycle.socket_fd);
        //cycle.accept_events[i].data.fd = -1;
        return RETURN_ERR;
    }else{
        printf("read fininsh! \n");
        record_log("read fininsh! \n\0");

        epoll_tmp->read_buf[n] = '\0';
        err_msg=(char *)malloc(1024*sizeof(char));
        sprintf(err_msg,"read %s\n\0",(char *)epoll_tmp->read_buf);
        record_log(err_msg,n);
        free(err_msg);
        err_msg=NULL;
      //record_log(read_log);
    }
    return RETURN_SUC;
}

//connect事件后写入连接中的数据
int conn_write(struct epoll_current *epoll_tmp){
    //char *line;
    int sock_fd;

    record_log( "EPOLLOUT\n\0");

    sock_fd = epoll_tmp->cur_event.data.fd;

    //给这个文件描述符加互斥锁
    flock(epoll_tmp->cur_event.data.fd,LOCK_EX);
    write(sock_fd, epoll_tmp->write_buf, 30);
    //给这个文件描述符解除互斥锁
    flock(epoll_tmp->cur_event.data.fd,LOCK_UN);
    return RETURN_SUC;
}

//注册连接事件,事件是EPOLLIN还是EPOLLOUT靠参数传入
void set_epoll_ctl(struct epoll_current *epoll_tmp,int epoll_op,__uint32_t events_tmp){
    struct epoll_event ev_tmp;
    //设置用于读操作的文件描述符
    ev_tmp.data.fd=epoll_tmp->cur_event.data.fd ;
    //设置用于注册的读操作事件
    #if ET
    ev_tmp.events=events_tmp|EPOLLET;
    #else
    ev_tmp.events=events_tmp;
    #endif
    //注册ev_tmp
    epoll_ctl(cycle.epl_lis_fd,epoll_op,epoll_tmp->cur_event.data.fd,&ev_tmp);
}

//子进程处理函数,取事件,做读写操作,接收主进程的管理
void cycle_process(){

    //当前进程所代表的事件
    struct epoll_current *epoll_tmp;

    while(1){
        //如果事件链表不为空,从事件链表中取出事件
        if(cycle.epoll_cycle->is_empty==0){
            epoll_tmp=(struct epoll_current *)malloc(sizeof(struct epoll_current));
            get_event(cycle.epoll_cycle,epoll_tmp);
        }else{
            //休眠一秒,重新开始
            sleep(1);
            continue;
        }
        //事件处理,有新的连接,处理连接事件
        if(epoll_tmp->cur_event.data.fd==cycle.socket_fd)
        {
            //accept连接事件
            if(accept_conn(epoll_tmp)==0){
                continue;
            }
            //为这个连接注册一个读事件
            set_epoll_ctl(epoll_tmp,EPOLL_CTL_ADD,EPOLLIN);
        }else if(epoll_tmp->cur_event.events&EPOLLIN)//接收到数据,读socket
        {
            if(conn_read(epoll_tmp)==0){
                continue;
            }
            //为这个连接注册一个写事件
            //set_epoll_ctl(epoll_tmp,EPOLL_CTL_MOD,EPOLLOUT);
        }else if(epoll_tmp->cur_event.events&EPOLLOUT)//有数据待发送,写socket
        {
            if(conn_write(epoll_tmp)==0){
                continue;
            }
            //为这个连接注册一个写事件
            //set_epoll_ctl(epoll_tmp,EPOLL_CTL_MOD,EPOLLIN);
        }
        //释放内存
        free((void *)epoll_tmp);
        epoll_tmp=NULL;
    }
}

//父进程处理函数,等待事件,放入事件链表,继续等待事件
void cycle_master(){
    int i;
    char *err_msg1;
  int epint=0;
    struct epoll_current epoll_tmp;

    if(cycle.epl_lis_fd>0){
        err_msg1=(char *)malloc(1024);
        //err_msg=(char *)malloc(1024);
        sprintf(err_msg1,"listen_fd : %d \n\0",cycle.epl_lis_fd);
        record_log(err_msg1);
        free(err_msg1);
        err_msg1=NULL;
    }else{
        record_log("listen_fd error !\n\0");
        return;
    }
    while(1){
        //等待事件
        epint=epoll_wait(cycle.epl_lis_fd,cycle.accept_events,WAIT_EPOLL_NUM,MX_WAIT_TIME);
        sleep(1);
        //将事件加入到事件循环链表中
        if(cycle.epoll_cycle->is_full==0){
            for(i=0;i<=epint;i++){
                epoll_tmp.cur_event.events=cycle.accept_events[i].events;
                epoll_tmp.cur_event.data.fd=cycle.accept_events[i].data.fd;
                set_event(cycle.epoll_cycle,&epoll_tmp);
            }
        }
        //等待信号,管理相应进程
    }
}

/*
增加一个父进程和N个子进程,父进程负责处理专心等待事件,并把事件放入事件链表,子进程负责处理事件链表中的事件
*/
int main(int argc, char *argv[]){

  int initStatus=0,sockStatus=0;

    //初始化系统
    initStatus=init_system();
    if(initStatus<=0){
        printf( "init system error!\n" ); 
        return RETURN_ERR;
    }
    //设置监听
    sockStatus=listen_socket();
    if(sockStatus<=0){
        printf( "init socket error!\n" ); 
        return RETURN_ERR;
    }

    int pro_num;
    pid_t father_pid;
    //pid_t pid;
    //得到父进程进程号
    father_pid=getpid();
    //创建子进程,根据WORK_PROCESS_NUM值,循环创建
    for(pro_num=0;pro_num<WORK_PROCESS_NUM;pro_num++){
        //子进程被创建之后跳出循环继续执行
        if(fork()==0){
            record_log("子进程!\0");
            break;
        }
        //父进程执行WORK_PROCESS_NUM次后跳出
    }
    //使用进程号判断是否是子进程,使用之后子进程和父进程分别走到不同的函数
    if(father_pid!=getpid()){
        //子进程执行自己的业务
        cycle_process();
    }else{
        //父进程执行自己的业务
        cycle_master();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值