Reactor网络模型核心思想探秘( 四 )

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进行分离呢?




推荐阅读