Redis网络库源码分析(2)之启动服务器
一、从main开始
main
函数定义在server.c
中,它的内容如下:
//server.c
int main()
{
signal(SIGPIPE, SIG_IGN);
//忽略SIGPIPE信号,防止给一个已经关闭socket的客户端连续两次发送数据导致SIGPIPE信号
//的产生,它的默认做法是终止进程。
server_t server; //创建一个server
bzero(&server, sizeof(server));
server.backlog = DEFAULT_LISTEN_BACKLOG; //设置backlog的大小
server.max_client_count = DEFAULT_MAX_CLIENT_COUNT; //设置最大的客户端连接数
server.port = DEFAULT_LISTEN_PORT; //设置默认的监听端口
init_server(&server); //初始化
wait_server(&server); //实际上进入了loop循环
return 0;
}
现在我们去看下定义的server_t
到底是什么东东?
//server.h
typedef struct {
aeEventLoop *loop; //最核心的时间循环
int listen_fd; //监听fd,socket函数返回
int port; //默认的监听端口
int backlog; //listen函数第二个参数backlog的大小
int max_client_count; //最大的客户端连接数
char err_info[ANET_ERR_LEN]; //err信息
} server_t;
是一个非常简单的服务器定义。最核心的是 aeEventLoop
,它是整个事件循环的结构体,我们现在看看它里面有什么:
//ae.h
/* State of an event based program */
typedef struct aeEventLoop {
int maxfd; /* 当前注册的最大文件描述符 */
int setsize; /* 监控的最大文件描述符数 */
long long timeEventNextId; /* 定时事件ID */
time_t lastTime; /* 最近一次处理定时事件的时间 */
aeFileEvent *events; /* 注册事件链表 */
aeFiredEvent *fired; /* 发生事件链表 */
aeTimeEvent *timeEventHead; /* 定时事件链表*/
int stop; /* 是否停止循环*/
void *apidata; /* 特定接口的特定数据*/
aeBeforeSleepProc *beforesleep; /*在sleep之前执行的程序*/
} aeEventLoop;
/* File event structure 事件结构体*/
typedef struct aeFileEvent {
int mask; /* 事件码:可读/可写 */
aeFileProc *rfileProc; /* 读事件的处理函数*/
aeFileProc *wfileProc; /* 写事件的处理函数*/
void *clientData; /* 用于传递server和client实例给相应函数*/
} aeFileEvent;
/* Time event structure 定时事件结构体*/
typedef struct aeTimeEvent {
long long id; /* 定时事件id */
long when_sec; /* 秒 */
long when_ms; /* 毫秒 */
aeTimeProc *timeProc; /* 定时事件处理程序*/
aeEventFinalizerProc *finalizerProc;
void *clientData; /* 用于传递server和client实例给相应函数*/
struct aeTimeEvent *next; /* 下一个节点 */
} aeTimeEvent;
/* A fired event 发生了事件的结构体*/
typedef struct aeFiredEvent {
int fd; /* fd */
int mask; /* 发生事件的掩码 (读/写)*/
} aeFiredEvent;
基本上这个结构体就能表示我们服务器在运行期间的数据结构了。
二、init_server 初始化server
void init_server(server_t *server)
{
server->loop = aeCreateEventLoop(server->max_client_count);
/* 为loop中各类数据结构申请空间 */
//aeCreateTimeEvent(loop, 1000, serverCron, NULL, NULL);
server->listen_fd = anetTcpServer(server->err_info, server->port, NULL, server->backlog);
/* 创建listen_fd 实际上调用socket函数 */
if (server->listen_fd != ANET_ERR) {
anetNonBlock(server->err_info, server->listen_fd); /*设置非阻塞*/
}
/*将 listen_fd 注册到epoll的实例上,事件处理函数为acceptTcpHandler*/
if (aeCreateFileEvent(server->loop, server->listen_fd, AE_READABLE, acceptTcpHandler, server) != AE_ERR) {
char conn_info[64];
anetFormatSock(server->listen_fd, conn_info, sizeof(conn_info));
printf("listen on: %s\n", conn_info);
}
}
三、wait_server 开始进入loop循环
void wait_server(server_t *server)
{
aeMain(server->loop); //是一个while循环,不断循环处理
aeDeleteEventLoop(server->loop); //如果出了循环,就删除loop
}
void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = 0; //设置停止标志为0,表示不停止
while (!eventLoop->stop) { //如果没有被设置为1
if (eventLoop->beforesleep) {
eventLoop->beforesleep(eventLoop);
}
aeProcessEvents(eventLoop, AE_ALL_EVENTS); //整个事件处理核心函数,实际上就再不断轮询这个函数
}
}
至此,我们的服务器算是启动起来了,它目前完成的是将listen_fd
注册到了epoll
的结构上,下次如果有连接请求我们就可以处理了。
Redis网络库源码分析(2)之启动服务器的更多相关文章
- Redis网络库源码分析(1)之介绍篇
一.前言 Redis网络库是一个单线程EPOLL模型的网络库,和Memcached使用的libevent相比,它没有那么庞大,代码一共2000多行,因此比较容易分析.其实网上已经有非常多有关这个网络库 ...
- Redis网络库源码分析(3)之ae.c
一.aeCreateEventLoop & aeCreateFileEvent 上一篇文章中,我们已经将服务器启动,只是其中有些细节我们跳过了,比如aeCreateEventLoop函数到底做 ...
- 第08课:【实战】Redis网络通信模块源码分析(1)
我们这里先研究redis-server端的网络通信模块.除去Redis本身的业务功能以外,Redis的网络通信模块实现思路和细节非常有代表性.由于网络通信模块的设计也是Linux C++后台开发一个很 ...
- 第10课:[实战] Redis 网络通信模块源码分析(3)
redis-server 接收到客户端的第一条命令 redis-cli 给 redis-server 发送的第一条数据是 *1\r\n\$7\r\nCOMMAND\r\n .我们来看下对于这条数据如何 ...
- Redis事件库源码分析
由于老大在新项目中使用redis的事件库代替了libevent,我也趁着机会读了一遍redis的事件库代码,第一次读到“优美,让人愉快”的代码,加之用xmind制作的类图非常帅,所以留文纪念. Red ...
- 第09课:【实战】Redis网络通信模块源码分析(2)
侦听 fd 与客户端 fd 是如何挂载到 EPFD 上去的 同样的方式,要把一个 fd 挂载到 EPFD 上去,需要调用系统 API epoll_ctl ,搜索一下这个函数名.在文件 ae_epoll ...
- # Volley源码解析(二) 没有缓存的情况下直接走网络请求源码分析#
Volley源码解析(二) 没有缓存的情况下直接走网络请求源码分析 Volley源码一共40多个类和接口.除去一些工具类的实现,核心代码只有20多个类.所以相对来说分析起来没有那么吃力.但是要想分析透 ...
- JVM源码分析之JVM启动流程
原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 “365篇原创计划”第十四篇. 今天呢!灯塔君跟大家讲: JVM源码分析之JVM启动流程 前言: 执行Java类的main方法,程序就能运 ...
- Tomcat源码分析之—具体启动流程分析
从Tomcat启动调用栈可知,Bootstrap类的main方法为整个Tomcat的入口,在init初始化Bootstrap类的时候为设置Catalina的工作路径也就是Catalina_HOME信息 ...
随机推荐
- Linux系列(10) - 命令搜索命令whereis与which
whereis 只能搜索系统命令,不能搜索自己凭空创建的普通文件 命令格式: whereis [命令名] 选项: -b:只查找可执行文件 -m:只查找帮助文件 which 搜索命令所在路径及别名:不是 ...
- 接口Mock测试
什么是Mock测试? Mock 测试就是在测试过程中,对于某些不容易构造(如 HttpServletRequest 必须在Servlet 容器中才能构造出来)或者不容易获取的比较复杂的对象(如 JDB ...
- 直接取PHP二维数组里面的值
具体是这样的,如下一个二维数组,是从库中读取出来的. $user = array( 0 => array( 'id' => 1, 'name' => '张三', 'email ...
- P4831-Scarlet loves WenHuaKe【组合数学】
正题 题目链接:https://www.luogu.com.cn/problem/P4831 题目大意 \(n*m\)的网格上放置\(2n\)个炮,要求互不能攻击. 数据满足\(n\leq m\leq ...
- 牛客练习赛71E-神奇的迷宫【点分治,NTT】
正题 题目链接:https://ac.nowcoder.com/acm/contest/7745/E 题目大意 给出\(n\)个点的一棵树,每个点有一个选择权重\(a_i\)(有\(\frac{a_i ...
- Windows环境下搭建Hadoop(2.6.0)+Hive(2.2.0)环境并连接Kettle(6.0)
前提:配置JDK1.8环境,并配置相应的环境变量,JAVA_HOME 一.Hadoop的安装 1.1 下载Hadoop (2.6.0) http://hadoop.apache.org/release ...
- vue项目中的element-ui地区级联选择器加详细地址push到对象中不显示的问题
想要实现级联选择器el-cascader和输入框el-input共同组成的详细地址,添加数据时弹出el-drawer嵌套el-form弹窗,然后在el-form添加数据提交后push到el-table ...
- vue 移动端项目切换页面,页面置顶
之前项目是pc端是使用router的方式实现置顶的 //main.js router.afterEach((to, from, next) => { window.scrollTo(0, 0) ...
- [源码解析] PyTorch 流水线并行实现 (5)--计算依赖
[源码解析] PyTorch 流水线并行实现 (5)--计算依赖 目录 [源码解析] PyTorch 流水线并行实现 (5)--计算依赖 0x00 摘要 0x01 前文回顾 0x02 计算依赖 0x0 ...
- Java8新特性——Lambda 表达式
Lambda 表达式 Lambda 表达式的实质属于函数式编程. 语法格式为:(parameters) -> expression ...