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信息 ...
随机推荐
- openFeign夺命连环9问,这谁受得了?
1.前言 前面介绍了Spring Cloud 中的灵魂摆渡者Nacos,和它的前辈们相比不仅仅功能强大,而且部署非常简单. 今天介绍一款服务调用的组件:OpenFeign,同样是一款超越先辈(Ribb ...
- Java面向对象系列(1)- 什么是面向对象
面向过程 & 面向对象 面向过程思想 步骤清晰清楚,第一步做什么,第二步做什么-- 面对过程适合处理一些较为简单的问题 面向对象思想 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分 ...
- Orchard Core 配置项说明
Orchard Core使用IShellConfiguration扩展了ASP.NET Core IConfiguration,以允许在应用程序范围的配置之上进行特定于租户的配置.虽然本文档使用Orc ...
- selenium--多窗口
多窗口/句柄 有些页面的链接打开后,会重新打开一个窗口,对于这种情况,想在新页面上操作,就得先切换窗口了.获取窗口的唯一标识用句柄表示,所以只需要切换句柄,我们就能在多个页面上灵活自如的操作了. 1. ...
- 树莓派使用python+继电器控制220V灯泡
需要的材料 1.继电器:继电器是一种电控制器件,它实际上是用小电流去控制大电流运作的一种"自动开关",我们这里用它来控制电灯.控制了继电器就等于控制了电灯. 我购买的是某宝上3块钱 ...
- Spring源码之AOP的使用
Spring往期精彩文章 Spring源码搭建 Spring源码阅读一 前言 我们都知道Java是一门面向对象(OOP)的语言,所谓万物皆对象.但是它也存在着一些个弊端:当你需要给多个不具有继承关系的 ...
- 定制个机器人帮你和Ta聊天
自动聊天示例 这是基于200万聊天记录训练出来的,你可以用自己和女朋友的记录训练了试试效果 至于微信机器人怎么用,你可以 GitHub 搜搜看哈 聊天1: user: 在吗? bot: 在 user: ...
- 重修 Tarjan
Tarjan是谁 Tarjan's SCCs(有向图强连通分量)algorithm 给定⼀个有向图 \(G\),若存在 \(rt\in V\),满⾜从 \(rt\) 出发能到达 \(V\) 中的所有的 ...
- 一次OutOfMemoryError: GC overhead limit exceeded
现象: 由于需要将mysql表中的过期数据在凌晨定时读取出过滤后转入到MongoDB,一个转换SQL达到百行,而且有几十个,集中运行后程序反馈异常: Handler dispatch failed; ...
- 洛谷4172 WC2006水管局长(LCT维护最小生成树)
这个题和魔法森林感觉有很相近的地方啊 同样也是维护一个类似最大边权最小的生成树 但是不同的是,这个题是有\(cut\)和询问,两种操作.... 这可如何是好啊? 我们不妨倒着来考虑,假设所有要\(cu ...