工作之余,重温了一下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();
}
}