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信息 ...
随机推荐
- vs code安装leetcode插件
vs code 安装不成功啊 1.首先确保有node.js 10+,没有的话去官网下载,安装就可以,安装好之后在cmd命令行中输入: node -v 若出现相关版本信息说明安装成功 2.由于leetc ...
- P6177-Count on a tree II/[模板]树分块
正题 题目链接:https://www.luogu.com.cn/problem/P6177 题目大意 \(n\)个点的一棵树\(m\)次询问树上颜色. 强制在线 \(1\leq n\leq 4\ti ...
- ARC106E-Medals【hall定理,高维前缀和】
正题 题目链接:https://atcoder.jp/contests/arc106/tasks/arc106_e 题目大意 \(n\)个员工,第\(i\)个在\([1,A_i]\)工作,\([A_i ...
- UOJ#33-[UR #2]树上GCD【长链剖分,根号分治】
正题 题目链接:https://uoj.ac/problem/33 题目大意 给出\(n\)个点的一棵树 定义\(f(x,y)=gcd(\ dis(x,lca),dis(y,lca)\ )\). 对于 ...
- P4643-[国家集训队]阿狸和桃子的游戏【结论】
正题 题目链接:https://www.luogu.com.cn/problem/P4643 题目大意 给出\(n\)个点\(m\)条边的无向图,两个人轮流选择一个未被选择的点加入点集. 然后每个人的 ...
- springweb项目自定义拦截器修改请求报文头
面向切面,法力无边,任何脏活累活,都可以从干干净净整齐划一的业务代码中抽出来,无非就是加一层,项目里两个步骤间可以被分层的设计渗透成筛子. 举个例子: 最近我们对接某银行接口,我们的web服务都是标准 ...
- JVM-对象的实例化,内存布局与访问定位
1.对象的实例化 提到对象的实例化,我们可能会想到几个问题.对象在JVM中是怎么存储的?对象里面有什么?接下来,我们就来探讨一下对象的实例化以及回答一下这两个问题. 首先我们用图例来说明对象的实例化: ...
- iOS实现XMPP通讯(二)XMPP编程
项目概述 这是一个可以登录jabber账号,获取好友列表,并且能与好友进行聊天的项目. 使用的是第三方库XMPPFramework框架来实现XMPP通讯. 项目地址:XMPP-Project 项目准备 ...
- 一次OutOfMemoryError: GC overhead limit exceeded
现象: 由于需要将mysql表中的过期数据在凌晨定时读取出过滤后转入到MongoDB,一个转换SQL达到百行,而且有几十个,集中运行后程序反馈异常: Handler dispatch failed; ...
- CTF入门记录(1
(https://ctf-wiki.org) 00 基础了解 CTF简介 (wolai.com) 00-1 CTF题目类型 Web 大部分情况下和网.Web.HTTP等相关技能有关. Web攻防的一些 ...