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信息 ...
随机推荐
- Jmeter系列(28)- 性能指标(1) | 常见性能指标
TPS 概念 TPS (transaction per second):意思是每秒事务数,具体事务的定义,都是人为的,可以一个接口.多个接口.一个业务流程等等.一个事务是指事务内第一个请求发送到接收到 ...
- xmind使用技巧
xmind看似每个人都会使用,但是掌握一些小技巧,能够有效提升工作效率. 多行复制粘贴 在xmind中选中多行,复制然后可以直接粘贴到excel.word当中. 在excel.word选中多行,复制然 ...
- php文件加密(screw方式)
1.上传已经生成好的执行文件. 2.上传扩展文件到目录: /usr/lib64/php/modules 3.上传配置文件到目录: /etc/php.d 4.执行 ./screw a.php 生成加密后 ...
- P6113-[模板]一般图最大匹配【带花树】
正题 题目链接:https://www.luogu.com.cn/problem/P6113 题目大意 给出一张无向图,求最大匹配. \(1\leq n\leq 10^3,1\leq m\leq 5\ ...
- 提问式复习:图文回顾 redo log 相关知识
原文链接:提问式复习:图文回顾 redo log 相关知识 1.如何提升 redo日志 的写性能? 为了保证 redo日志 不丢失,会在磁盘中开辟一块空间将日志保存起来.但是这样会有一个问题,磁盘的读 ...
- 鲲鹏展翅|SphereEx 获华为鲲鹏技术认证
SphereEx Data Middleware 通过了华为鲲鹏技术认证并加入鲲鹏展翅伙伴计划,未来 SphereEx Data Middleware 产品将继续以分布式能力为基础,以数据安全.分布式 ...
- Apache ShardingSphere 元数据加载剖析
唐国城 小米软件工程师,主要负责 MIUI 浏览器服务端研发工作.热爱开源,热爱技术,喜欢探索,热衷于研究学习各种开源中间件,很高兴能参与到 ShardingSphere 社区建设中,希望在社区中努力 ...
- Python中字符串常用方法
capitalize() String.capitalize() 将字符串首字母变为大写 name = 'xiaoming' new_name = name.capitalize() print(ne ...
- GoLang设计模式11 - 备忘录模式
备忘录模式是一种行为型设计模式.这种模式允许我们保存对象在某些关键节点时的必要信息,以便于在适当的时候可以将之恢复到之前的状态.通常它可以用来帮助设计撤销/恢复操作. 下面是备忘录设计模式的主要角色: ...
- SpringBoot 后端接收前端传值的方法
1.通过HttpServletRequest接收,适用于GET 和 POST请求方式 通过HttpServletRequest对象获取请求参数 @RestController @Reque ...