perror("create-server-fail");
return -1;
}
make_nonblocking(sockfd);
epfd = epoll_create1(1);
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = sockfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
struct epoll_event events[1024] = {0};
conn_map[sockfd].rlen = 0;
conn_map[sockfd].wlen = 0;
conn_map[sockfd].fd = sockfd;
conn_map[sockfd].call_t.accept_call = accept_callback;
conn_map[sodkfd].send_call = send_callback;
memset(conn_map[sockfd].rbuf, 0, BUF_LEN);
memset(conn_map[sockfd].wbuf, 0, BUF_LEN);
while(1) {
int nready = epoll_wait(epfd, events, 1024, -1);
int i = 0;
for (i = 0; i < nready; i++) {
int connfd = events[i].data.fd;
if (events[i].events & EPOLLIN) {
int count = conn_map[connfd].call_t.recv_call(connfd);
printf("recv-count:%d\n", count);
} else if (events[i].events & EPOLLOUT) {
int count= conn_map[connfd].send_call(connfd);
printf("send-count:%d\n", count);
}
}
}
}
你可以想一下 , 我们注册的是call_t.accept_call,但在调用的时候确是call_t.recv_call , 为什么这样可行?
我们在网络编程系列文章中,单独为accept抽象出了一个对象,你可以对比一下这两种实现方式,看看它们有什么区别?在系列文件中我们为什么要单独抽象出一个accepter对象呢?
可以看到,最后主循环中的逻辑 , 只有两个分支,这两个分支代表了两种事件 , 这种通过事件驱动的网络模型便是Reactor网络模型 。本文为了容易理解,将代码进行了精简 。在实际的工程中我们还要考虑诸多情况 。比如,上面的代码只支持epoll , 我们是不是可以将事件驱动相关的代码抽象成单独的组件,让其可以支持其它的事件模型 。
【Reactor网络模型核心思想探秘】本文虽然代码简单,但Reactor网络模型的实现基本上都逃脱不了这个套路 , 只是在此基础上可能会将各个部分进行单独的封装,比如我们在网络编程系列文章中就将channel和map进行了抽象,让它能适配各种场景 。
总结
reactor网络模型是网络编程中非常重要的一种编程思想,本文通过一个简短的示例试图讲明白reactor网络编程模型的核心思想 。当然,本文的实现还不是很完善 , 比如在调用回调函数的时候还是传入了fd,我们是否可以不需要这个参数,彻彻底底地和IO进行分离呢?
推荐阅读
- 网络信息时代如何找到你想找的人呢
- 笔记本无线网卡无法连接网络怎么办
- 如花是谁啊,网络人物如花是谁啊?
- 小米手机怎么开网络加速,小米手机显示网络加速中
- 什么是蜂窝网络,什么是蜂窝网?
- 问道100五法怎么过,问道网络游戏如何游历师门
- 早期网络歌手近况:英年早逝、已被判刑、转战幕后,青春终会散场
- 如何渲染线框模型
- 网络用语需句斟字酌!避免“乌龙事件”避免踩雷
- 当女明星出演网络电影,“照妖镜”下丑态百出,年轻时却都是神颜