/*
* @Author: huichangren [email protected]
* @Date: 2022-07-28 22:14:36
* @LastEditors: huichangren [email protected]
* @LastEditTime: 2022-07-29 00:16:40
* @FilePath: /epoll_reactor/main.cpp
* @Description: epoll 与reactor模型
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static const int MAX_EVENTS = 1024; //最大事件数
static const int BUFFER_LEN = 128; //缓存大小
static const int SERVER_PORT = 8080; //服务端口
void RecvData(int fd, int events, void *arg); //读数据回调
void SendData(int fd, int events, void *arg); //发数据回调
/*
* m_status:1表示在监听事件中,0表示不在
* last_active:记录最后一次响应时间,做超时处理
*/
struct MyEvent
{
typedef void (*EventCallBack)(int ,int , void *) ;
int m_fd; //文件描述符
int m_events; //事件类型:EPOLLIN|EPOLLOUT
void *m_args; //回调参数
EventCallBack m_callback; //事件回调
int m_status;
char m_buf[BUFFER_LEN]; //缓存
int m_buff_len; /缓存中数据的大小
long m_last_active; //上次激活的时间戳
};
struct MyEvent myevents[MAX_EVENTS+1]; //事件集合
int global_epoll_fd; //epoll_create返回的句柄
//设置事件接口
void SetEvent(MyEvent *event,int fd,void (*call_back)(int ,int , void *),void *arg)
{
event->m_fd = fd;
event->m_callback = call_back;
event->m_events = 0;
event->m_args = arg;
event->m_status = 0;
memset(event->m_buf,0,sizeof(event->m_buf));
event->m_buff_len = 0;
}
//添加事件
void AddEvent(int epoll_fd,int events,MyEvent *event)
{
struct epoll_event ep_event;
memset(&ep_event,0,sizeof(ep_event));
int option =0;
ep_event.data.ptr = event; //让epoll事件指向自定义事件
ep_event.events = event->m_events = events; //给事件赋值
if (event->m_status == 1)
{
option = EPOLL_CTL_MOD; //改变epoll中的事件
}else
{
option = EPOLL_CTL_ADD;
event->m_status = 1;
}
if (epoll_ctl(epoll_fd, option, event->m_fd, &ep_event) < 0)
{
printf("event add failed [fd=%d], events[%d]\n", event->m_fd, events);
}
else
{
printf("event add OK [fd=%d], op=%d, events[%0X]\n", event->m_fd, option, events);
}
}
//删除事件
void DelEvent(int epoll_fd, MyEvent *event)
{
struct epoll_event ep_event;
memset(&ep_event,0,sizeof(ep_event));
if (event->m_status != 1)
return;
ep_event.data.ptr = event;
event->m_status = 0;
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, event->m_fd, &ep_event);
}
//接受链接接口
void AcceptConn(int listen_fd, int events, void*args)
{
struct sockaddr_in cin;
socklen_t len = sizeof(cin); //对端地址
int conn_fd; //链接fd
if((conn_fd= accept(listen_fd,(struct sockaddr*)&cin,&len))==-1)
{
if (errno != EAGAIN && errno != EINTR) {
fprintf(stderr,"errno EAGAIN && EINTR signal happen");
return;
}
fprintf(stderr,"accept failed!");
return;
}
int i = 0;
do
{
for ( i = 0; i < MAX_EVENTS; i++) //找到事件集合中事件是空的事件的index i
{
if (myevents[i].m_status==0)
{
break;
}
}
if (i == MAX_EVENTS)//超出链接数
{
printf("%s: max connect limit[%d]\n", __func__, MAX_EVENTS);
break;
}
int ret = 0;
if ((ret = fcntl(conn_fd,F_SETFL,O_NONBLOCK))<0)
{//设置非阻塞
printf("%s: set nonblocking failed, %s\n", __func__, strerror(errno));
break;
}
SetEvent(&myevents[i], conn_fd, RecvData, &myevents[i]); //添加事件到事件集合
AddEvent(global_epoll_fd, EPOLLIN, &myevents[i]); //添加读事件触发
} while (0);
printf("new connect [%s:%d][time:%ld], pos[%d]\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), myevents[i].m_last_active, i);
return;
}
void RecvData(int fd,int events,void *arg)
{
struct MyEvent *event = (struct MyEvent *)arg;
int len = recv(fd, event->m_buf, sizeof(event->m_buf), 0); //从fd中读取数据到event中buf
DelEvent(global_epoll_fd, event); //数据读完了,就把从事件集合中删除
if (len > 0) {
event->m_buff_len = len;
event->m_buf[len] = '\0';
printf("C[%d]:%s\n", fd, event->m_buf);
/* 转换为发送事件 */
SetEvent(event, fd, SendData, event);
AddEvent(global_epoll_fd, EPOLLOUT, event);
}
else if (len == 0) {
close(event->m_fd);
}
else {
close(event->m_fd);
printf("recv[fd=%d] error[%d]:%s\n", fd, errno, strerror(errno));
}
}
void SendData(int fd, int events, void *arg)
{
struct MyEvent *ev = (struct MyEvent *)arg;
int len = send(fd, ev->m_buf, ev->m_buff_len, 0);
DelEvent(global_epoll_fd, ev);
if (len > 0) {
printf("send[fd=%d], [%d]%s\n", fd, len, ev->m_buf);
SetEvent(ev, fd, RecvData, ev);
AddEvent(events, EPOLLIN, ev);
}
else {
close(ev->m_fd);
printf("send[fd=%d] error %s\n", fd, strerror(errno));
}
}
void InitListenSocket(int efd, short port)
{
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
fcntl(listen_fd, F_SETFL, O_NONBLOCK);
SetEvent(&myevents[MAX_EVENTS], listen_fd, AcceptConn, &myevents[MAX_EVENTS]);//添加处理链接的事件
AddEvent(efd, EPOLLIN, &myevents[MAX_EVENTS]);
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(port);
int ret = bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin));
if (ret < 0)
{
fprintf(stderr,"bind error");
return;
}
ret = listen(listen_fd, 10);
if (ret < 0)
{
fprintf(stderr,"listen failed");
return;
}
}
int main(int argc, char *argv[])
{
unsigned short port = SERVER_PORT;
if (argc == 2)
port = atoi(argv[1]);
global_epoll_fd = epoll_create(MAX_EVENTS+1);
if (global_epoll_fd <= 0)
printf("create efd in %s err %s\n", __func__, strerror(errno));
InitListenSocket(global_epoll_fd, port);
/* 事件循环 */
struct epoll_event events[MAX_EVENTS+1];
printf("server running:port[%d]\n", port);
int checkpos = 0, i;
while (1) {
long now = time(NULL);
for (i = 0; i < 100; i++, checkpos++) {
if (checkpos == MAX_EVENTS)
checkpos = 0;
if (myevents[checkpos].m_status != 1)
continue;
long duration = now - myevents[checkpos].m_last_active;
if (duration >= 60) {
close(myevents[checkpos].m_fd);
printf("[fd=%d] timeout\n", myevents[checkpos].m_fd);
DelEvent(global_epoll_fd, &myevents[checkpos]);
}
}
/* 等待事件发生 */
int nfd = epoll_wait(global_epoll_fd, events, MAX_EVENTS+1, 1000);
if (nfd < 0) {
printf("epoll_wait error, exit\n");
break;
}
for (i = 0; i < nfd; i++) {
struct MyEvent *ev = (struct MyEvent *)events[i].data.ptr; //拿到ptr指向的自定义事件
if ((events[i].events & EPOLLIN) && (ev->m_events & EPOLLIN)) {
ev->m_callback(ev->m_fd, events[i].events, ev->m_args); //执行里面的回调
}
if ((events[i].events & EPOLLOUT) && (ev->m_events & EPOLLOUT)) {
ev->m_callback(ev->m_fd, events[i].events, ev->m_args);
}
}
}
return 0;
}