Skynet源码解析:启动流程与核心组件
作者:海底来的沙3 | 来源:互联网 | 2024-11-25 16:23
本文详细解析Skynet的启动流程,包括配置文件的读取、环境变量的设置、主要线程的启动(如timer、socket、monitor和worker线程),以及消息队列的实现机制。
### Skynet 启动流程
Skynet 是一个轻量级的游戏服务器框架,其启动过程主要涉及以下几个步骤:
1. **读取配置文件**:Skynet 只有一个 `skynet-src` 目录,通过 `./skynet ./example/config` 命令启动。`skynet_main.c` 文件负责读取配置文件,并设置环境变量。
2. **初始化环境**:读取配置文件后,`skynet_start.c` 中的 `skynet_start` 函数会被调用,用于初始化基础服务,包括 timer、socket、module 和 mq 等数据结构。
3. **启动线程**:`skynet_start` 函数会调用 `_start` 函数,启动 timer 线程、socket 线程、monitor 线程以及多个 worker 线程。worker 线程的数量可以在配置文件中指定,默认为 8 个。
### Skynet 运行机制
Skynet 的核心在于其消息队列机制。每个服务都需要设置一个 callback 函数,用于处理接收到的消息。消息会被压入该服务的消息队列中,由 worker 线程从全局队列中取出并处理。
#### Socket 服务
游戏服务器通常会启动一个 socket 服务,交给 `gate.so` 管理。socket 服务可以接收外部消息并传递给内部服务进行处理。
### Monitor 机制
Skynet 的监控机制相对简单,主要通过 `skynet_monitor.c` 和 `skynet_monitor.h` 实现。当服务可能陷入死循环时,会记录一条日志。每次消息派发时,会调用 `skynet_monitor_trigger` 函数两次,分别在消息派发前和派发后。
### Timer 机制
Skynet 的定时器功能在游戏开发中非常常用。其核心实现在 `skynet-timer.c` 和 `skynet-timer.h` 中。定时器分为两个部分存储:一部分在 `near` 数组中,另一部分在二维数组中,分为四个级别。每 2.5 毫秒,timer 线程会更新一次时间,并触发相应的定时器事件。
### 主要函数解析
1. **main 函数**:作为 Skynet 进程的入口点,`main` 函数需要一个配置文件路径作为参数。它先进行内存分配,加载配置文件内容,设置环境变量,然后调用 `skynet_start` 函数。
2. **skynet_start 函数**:根据配置确定服务是否以后台方式启动,初始化 timer、socket、module 和 mq 数据结构,创建和注册日志 logger 服务,最后调用 `start` 函数。
3. **start 函数**:启动 timer、socket、monitor 和 worker 线程。所有线程启动完成后,进入 `pthread_join` 等待线程终止。
### 消息队列实现
消息队列是 Skynet 的核心功能之一,其实现细节如下:
```cpp
#define SKYNET_MESSAGE_QUEUE_H
#include
#include
// 消息结构体
struct skynet_message {
uint32_t source; // 消息来源
int session; // 会话标识
void *data; // 消息体
size_t sz; // 消息长度
};
// 全局消息队列
struct global_queue {
struct message_queue *head; // 链表头
struct message_queue *tail; // 链表尾
struct spinlock lock; // 自旋锁
};
// 创建消息队列
struct message_queue *skynet_mq_create(uint32_t handle);
// 消息入队
void skynet_mq_push(struct message_queue *q, struct skynet_message *message);
// 消息出队
int skynet_mq_pop(struct message_queue *q, struct skynet_message *message);
// 获取队列长度
int skynet_mq_length(struct message_queue *q);
// 扩展队列
static void expand_queue(struct message_queue *q);
// 初始化全局队列
void skynet_mq_init();
```
### 总结
通过上述分析,可以看出 Skynet 的消息队列机制非常高效且灵活。全局消息队列采用链表实现,而服务消息队列则使用循环数组,支持动态扩展。这种设计使得 Skynet 能够高效地处理大量并发请求。
### 推荐资源
如果你对 Skynet 项目感兴趣,推荐参加一个实战训练营,内容涵盖多核并发编程、消息队列、线程池、actor 消息调度、网络模块实现、时间轮定时器、Lua/C 接口编程等。更多资料可加入 QQ 群:832218493 免费领取。
推荐阅读
-
本文介绍了一个项目中如何在Windows平台上实现多声道音频数据的采集,特别是针对DANTE音频接口的8路立体声音频通道。文章详细描述了使用Windows底层音频API进行音频采集的方法,并提供了一个具体的实现示例。 ...
[详细]
蜡笔小新 2024-12-16 18:43:24
-
本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ...
[详细]
蜡笔小新 2024-12-23 14:50:23
-
-
本文详细探讨了Redis中的数据结构和对象系统的实现,包括字符串、列表、集合、哈希表和有序集合等五种核心对象类型,以及它们所使用的底层数据结构。通过分析源码和相关文献,帮助读者更好地理解Redis的设计原理。 ...
[详细]
蜡笔小新 2024-12-25 04:11:22
-
Java并发编程实践目录并发编程01——ThreadLocal并发编程02——ConcurrentHashMap并发编程03——阻塞队列和生产者-消费者模式并发编程04——闭锁Co ...
[详细]
蜡笔小新 2024-12-21 12:39:07
-
微软Exchange服务器在新年伊始遭遇了一个类似于‘千年虫’的日期处理漏洞,导致邮件传输受阻。该问题主要影响配置了FIP-FS恶意软件引擎的Exchange 2016和2019版本。 ...
[详细]
蜡笔小新 2024-12-25 14:08:03
-
本文详细介绍了优化DB2数据库性能的多种方法,涵盖统计信息更新、缓冲池调整、日志缓冲区配置、应用程序堆大小设置、排序堆参数调整、代理程序管理、锁机制优化、活动应用程序限制、页清除程序配置、I/O服务器数量设定以及编入组提交数调整等方面。通过这些技术手段,可以显著提升数据库的运行效率和响应速度。 ...
[详细]
蜡笔小新 2024-12-22 16:20:33
-
本文将详细探讨RDMA架构中的关键组件——队列对(Queue Pair,简称QP),包括其基本概念、硬件与软件实现、QPC的作用、QPN的分配机制以及用户接口和状态机。通过这些内容,读者可以更全面地理解QP在RDMA通信中的重要性和工作原理。 ...
[详细]
蜡笔小新 2024-12-21 11:16:36
-
本文详细探讨了Linux系统中信号的生命周期,从信号生成到处理函数执行完毕的全过程,并介绍了信号编程中的注意事项和常见应用实例。通过分析信号在进程中的注册、注销及处理过程,帮助读者理解如何高效利用信号进行进程间通信。 ...
[详细]
蜡笔小新 2024-12-21 10:29:05
-
本文详细探讨了Java多线程与并发库的高级应用,结合空中网在挑选实习生时的面试题目,深入分析了相关技术要点和实现细节。文章通过具体的代码示例展示了如何使用Semaphore和SynchronousQueue来管理线程同步和任务调度。 ...
[详细]
蜡笔小新 2024-12-21 09:43:07
-
本文探讨了在Flask应用中通过优化后端架构来应对高并发请求,特别是针对Mysql 'too many connections' 错误的解决方案。我们将介绍如何利用Redis缓存、Gunicorn多进程和Celery异步任务队列来提升系统的性能和稳定性。 ...
[详细]
蜡笔小新 2024-12-21 09:21:49
-
本文深入探讨了UNIX/Linux系统中的进程间通信(IPC)机制,包括消息传递、同步和共享内存等。详细介绍了管道(Pipe)、有名管道(FIFO)、Posix和System V消息队列、互斥锁与条件变量、读写锁、信号量以及共享内存的使用方法和应用场景。 ...
[详细]
蜡笔小新 2024-12-20 10:14:51
-
本文探讨了如何通过一系列技术手段提升Spring Boot项目的并发处理能力,解决生产环境中因慢请求导致的系统性能下降问题。 ...
[详细]
蜡笔小新 2024-12-19 21:07:12
-
本文详细解析了2019年西安邀请赛中的一道树形动态规划题目——J题《And And And》。题目要求计算树中所有子路径异或值为0的集合数量,通过深入分析和算法优化,提供了高效的解决方案。 ...
[详细]
蜡笔小新 2024-12-19 15:29:11
-
本文探讨了大型服务端开发过程中常见的几个误区,包括异步任务处理不当、日志同步模式使用、网络操作未设置超时、缓存命中率及响应时间未统计、单一缓存模式、分布式缓存加锁不当以及团队管理上的误区,旨在帮助开发者避免这些常见错误。 ...
[详细]
蜡笔小新 2024-12-18 14:19:10
-
MainActivityimportandroid.app.Activity;importandroid.os.Bundle;importandroid.os.Handler;im ...
[详细]
蜡笔小新 2024-12-16 11:29:01
-