热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Skynet源码解析:启动流程与核心组件

本文详细解析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 免费领取。
推荐阅读
  • 电商高并发解决方案详解
    本文以京东为例,详细探讨了电商中常见的高并发解决方案,包括多级缓存和Nginx限流技术,旨在帮助读者更好地理解和应用这些技术。 ... [详细]
  • RTThread线程间通信
    线程中通信在裸机编程中,经常会使用全局变量进行功能间的通信,如某些功能可能由于一些操作而改变全局变量的值,另一个功能对此全局变量进行读取& ... [详细]
  • 本文总结了近年来在实际项目中使用消息中间件的经验和常见问题,旨在为Java初学者和中级开发者提供实用的参考。文章详细介绍了消息中间件在分布式系统中的作用,以及如何通过消息中间件实现高可用性和可扩展性。 ... [详细]
  • Centos7 Tomcat9 安装笔记
    centos7,tom ... [详细]
  • Nacos 0.3 数据持久化详解与实践
    本文详细介绍了如何将 Nacos 0.3 的数据持久化到 MySQL 数据库,并提供了具体的步骤和注意事项。 ... [详细]
  • RabbitMQ 核心组件解析
    本文详细介绍了RabbitMQ的核心概念,包括其基本原理、应用场景及关键组件,如消息、生产者、消费者、信道、交换机、路由键和虚拟主机等。 ... [详细]
  • 本文探讨了在SharePoint环境中使用BDC(Business Data Catalog)时遇到的问题及其解决策略,包括XML文件导入SSP后的不可见性问题以及与远程SQL Server 2005连接的难题。 ... [详细]
  • 本文详细介绍了在PHP中如何获取和处理HTTP头部信息,包括通过cURL获取请求头信息、使用header函数发送响应头以及获取客户端HTTP头部的方法。同时,还探讨了PHP中$_SERVER变量的使用,以获取客户端和服务器的相关信息。 ... [详细]
  • 本文详细介绍了如何在PHP中使用Memcached进行数据缓存,包括服务器连接、数据操作、高级功能等。 ... [详细]
  • Maven快照版本管理及更新策略详解
    本文深入探讨了Maven中的快照版本管理和更新策略,解释了快照版本与正式版本的区别,并提供了如何配置快照更新策略的方法,以确保项目依赖始终保持最新。 ... [详细]
  • 在CentOS 7中部署Nginx并配置SSL证书
    本文详细介绍了如何在CentOS 7操作系统上安装Nginx服务器,并配置SSL证书以增强网站的安全性。适合初学者和中级用户参考。 ... [详细]
  • 本文探讨了如何在PHP与MySQL环境中实现高效的分页查询,包括基本的分页实现、性能优化技巧以及高级的分页策略。 ... [详细]
  • 【小白学习C++ 教程】二十三、如何安装和使用 C++ 标准库
    【小白学习C++ 教程】二十三、如何安装和使用 C++ 标准库 ... [详细]
  • Kafka入门指南
    本文将详细介绍如何在CentOS 7上安装和配置Kafka,包括必要的环境准备、JDK和Zookeeper的配置步骤。 ... [详细]
  • oracle 对硬件环境要求,Oracle 10G数据库软硬件环境的要求 ... [详细]
author-avatar
海底来的沙3
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有