emo

emo

Skynet 源码分析-结构分析

源码地址:https://github.com/cloudwu/skynet

框架结构#

  • skynet-src:Skynet 的核心源码,包括主体框架、服务管理、网络通信、计时器等模块。
  • 3rd:Skynet 依赖的第三方库,包括 LuaJIT、luasocket 等。
  • config:Skynet 的配置文件目录。
  • example:Skynet 的示例代码目录,包括 echo 服务、pingpong 示例、socket 模块示例等。
  • luaclib:Skynet 的 C 扩展库,例如 cjson、protobuf 等。
  • lualib:Skynet 的 Lua 扩展库,例如 skynet、socket 等。
  • service:Skynet 的服务代码目录,包括各个服务的 Lua 源码、初始化脚本等。
  • test:Skynet 的测试代码目录。

核心模块#

  • skynet_main.c:Skynet 主函数,包括参数解析、初始化、启动服务等。
  • skynet.h:Skynet 的核心头文件,包括数据结构定义、函数声明等。
  • service-src:Skynet 服务管理模块,包括服务注册、服务查找、消息处理等。
  • lualib-src:Skynet Lua 扩展模块,包括 Lua 和 C 之间的交互函数等。
  • timer.c:Skynet 计时器模块,包括定时器的设置、删除等。
  • socket_server.c:Skynet 网络通信模块,包括 TCP/UDP 网络连接、消息处理等。
  • logger.c:Skynet 日志模块,包括日志的记录、输出等。
  • malloc_hook.c:Skynet 内存管理钩子,用于统计内存使用情况。

服务管理#

  • 注册服务:将服务注册到框架中,使得其他服务可以调用。
  • 查找服务:根据服务名查找对应的服务句柄。
  • 消息处理:处理来自其他服务的消息。

Lua 扩展模块#

  • skynet.lua:Skynet 的核心接口,包括服务注册、消息发送、定时器等。
  • socket.lua:网络通信模块,包括 TCP、UDP、HTTP 等协议的支持。
  • cjson.lua:JSON 解析库。
  • protobuf.lua:Google 的 Protobuf 库的 Lua 实现。

网络通信#

1. 网络模型

  • skynet_socket:Socket 的结构体,包括 Socket 的 ID、类型、地址等信息。
  • struct skynet_context:Actor 的上下文结构体,包括 Actor 的名字、消息队列等信息。
  • skynet_socket_poll:Socket 的轮询函数,用于处理网络事件。
  • skynet_socket_send:向指定的 Socket 发送数据。
  • skynet_socket_connect:向指定的地址和端口号连接 Socket。
  • skynet_socket_bind:绑定 Socket 到指定的地址和端口号。
  • skynet_socket_listen:开始监听 Socket。
  • skynet_socket_close:关闭指定的 Socket。

2. 网络通信

  • skynet_send:向指定的 Actor 发送一条消息,该函数会查找目标 Actor 并向其消息队列中添加一条消息。
  • skynet_socket_start:启动网络服务,并监听指定的端口号。
  • skynet_socket_poller:网络轮询函数,用于处理网络事件。
  • skynet_socket_udp:创建一个 UDP Socket,并绑定到指定的地址和端口号。
  • skynet_socket_udp_connect:将 UDP Socket 连接到指定的地址和端口号。
  • skynet_socket_udp_send:向指定的 UDP Socket 发送数据。
  • skynet_socket_udp_address:获取 UDP Socket 的地址信息。
  • skynet_socket_udp_close:关闭指定的 UDP Socket。

Actor 模型相关#

1. 消息队列

  • struct message:消息的结构体,包括消息源、目标、类型、数据等信息。

    消息队列中存储的是 message 结构体,该结构体包括消息源、目标、类型、数据等信息,方便消息的传递和处理。

  • struct message_queue:消息队列的结构体,包括消息队列头、尾指针、消息数量等信息。

    message_queue 结构体是消息队列的管理结构体,包括消息队列头、尾指针、消息数量等信息,用于管理消息队列中的消息,方便消息的添加、弹出等操作。

  • skynet_mq_push:向消息队列中添加一条消息。

    skynet_mq_push 函数用于向消息队列中添加一条消息,将消息添加到消息队列的尾部,方便消息的处理。

  • skynet_mq_pop:从消息队列中弹出一条消息。

    skynet_mq_pop 函数用于从消息队列中弹出一条消息,将消息从消息队列的头部弹出,方便消息的处理。

  • skynet_mq_length:获取消息队列中的消息数量。

    skynet_mq_length 函数用于获取消息队列中的消息数量,方便统计消息的数量。

  • skynet_mq_alloc:从内存池中分配一个消息队列。

    skynet_mq_alloc 函数用于从内存池中分配一个新的消息队列,用于消息的存储和管理。

  • skynet_mq_mark_release:标记消息队列为释放状态,当消息队列中的所有消息被处理完毕后,就可以将其释放回内存池。

    skynet_mq_mark_release 函数用于标记消息队列为释放状态,当消息队列中的所有消息被处理完毕后,就可以将其释放回内存池,方便内存的管理。

  • skynet_mq_release:释放标记为释放状态的消息队列。

    skynet_mq_release 函数用于释放标记为释放状态的消息队列,方便内存的管理。

2. Actor 模型通信机制

  • struct skynet_context:Actor 的上下文结构体,包括 Actor 的名字、消息队列等信息。

    skynet_context 结构体是 Actor 的上下文结构体,包括 Actor 的名字、消息队列等信息,用于管理 Actor 的状态和各种信息。

  • skynet_context_new:创建一个新的 Actor,并初始化其上下文结构体。

    skynet_context_new 函数用于创建一个新的 Actor,并初始化其上下文结构体,方便 Actor 的管理和使用。

  • skynet_context_release:释放 Actor 的上下文结构体。

    skynet_context_release 函数用于释放 Actor 的上下文结构体,方便内存的管理。

  • skynet_context_push:向 Actor 的消息队列中添加一条消息。

    skynet_context_push 函数用于向 Actor 的消息队列中添加一条消息,方便消息的传递和处理。

  • skynet_context_pop:从 Actor 的消息队列中弹出一条消息。

    skynet_context_pop 函数用于从 Actor 的消息队列中弹出一条消息,方便消息的处理。

  • skynet_context_handle_message:处理 Actor 的消息队列中的所有消息。

    skynet_context_handle_message 函数用于处理 Actor 的消息队列中的所有消息,方便消息的统一处理。

  • skynet_send:向指定的 Actor 发送一条消息,该函数会查找目标 Actor 并向其消息队列中添加一条消息。

    skynet_send 函数用于向指定的 Actor 发送一条消息,该函数会查找目标 Actor 并向其消息队列中添加一条消息,方便消息的传递和处理。

3. 消息的传递过程

  1. 发送方使用 skynet_send 向指定的 Actor 发送一条消息。

  2. Skynet 根据消息的目标 Actor 查找其上下文结构体,并向其消息队列中添加一条消息。

  3. 接收方使用 skynet_context_pop 从自己的消息队列中弹出一条消息,并进行处理。

日志模块#

  • 记录各个服务的运行状态、错误信息等。

内存管理#

Skynet 的内存管理模块采用了透明的内存池实现,可以有效地减少内存分配和释放的频率,提高内存使用效率。具体分析如下:

  1. 内存池的结构
  • struct mem_data:内存池中的一个块的结构体,包括前后链接、大小等信息。
  • struct mem_env:内存池的管理结构体,包括内存池的起始地址、结束地址、块的大小等信息。
  1. 内存池的创建
  • mem_init:初始化内存池的管理结构体,设置内存池的起始地址、结束地址、块的大小等信息。
  • mem_alloc:从内存池中分配一定大小的内存,返回内存池中一个空闲块的指针。
  • mem_free:将一块内存释放回内存池,将其标记为空闲块。
  1. 内存池的扩展
  • mem_newpool:在内存池管理结构体后面申请一块新的内存池,并将其加入内存池链表,以支持内存池的扩展。
  1. 内存池的使用
  • skynet_malloc:使用内存池分配一块指定大小的内存。
  • skynet_calloc:使用内存池分配一块指定大小的内存,并将其清零。
  • skynet_free:将一块指定的内存释放回内存池。
  1. 内存池的统计
  • mem_data_dump:输出内存池中各个块的使用情况。
  • mem_report:输出内存池的总体情况,包括使用率、总大小、空闲块数等。
  1. 内存池的原理

内存池的实现原理是将一块连续的内存分成若干大小相等的块,用前后链接将这些块串联起来,空闲块用一个链表连接,已分配的块则不在链接中。内存池的管理结构体包括内存池的起始地址、结束地址、块的大小等信息。在内存池中分配和释放内存时,只需要简单地修改链表的指针即可,不需要进行内存的分配和释放操作,以达到快速的内存分配和释放效果。同时,内存池的使用还可以降低内存碎片的产生,提高内存使用效率。

高并发、高吞吐、高性能分析#

  • skynet_socket_poller 使用了 I/O 多路复用模型,同时支持 epoll、kqueue、select 三种模式,可以有效地提高网络通信的并发处理能力。
  • Skynet 使用了非阻塞 I/O 模型,使用了底层操作系统提供的异步 I/O 函数,避免了 I/O 操作阻塞线程的情况,提高了系统的吞吐量和性能。
  • Skynet 使用了消息队列作为 Actor 之间通信的数据结构,避免了线程之间的竞争和锁的使用,进一步提高了系统的并发性和性能。
加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。