> For the complete documentation index, see [llms.txt](https://xd96dx.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://xd96dx.gitbook.io/docs/you-xi-kai-fa/skynet-cong-demo-dao-yuan-ma/skynet-yuan-ma-fen-xi-qi-dong-liu-cheng-zhi-chuang-jian-service.md).

# skynet 源码分析-启动流程之创建service

书接上文, 在加载了各种配置, 初始化全局变量(handle\_storage , global\_queue, env, module, timer, epoll\_socket) 之后, 接下来就要创建实际的service, 本文将详细讲述skynet 创建service 的流程

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FuXOvWXyai2UPio0OTQHV%2Fimage.png?alt=media&amp;token=f2bace91-5503-4563-933c-190aa33d67f4" alt=""><figcaption></figcaption></figure>

## 从 skynet\_context\_new 开始

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FUDqO5cLcThS8bDKu95b4%2Fimage.png?alt=media&amp;token=d53bc0be-b9ef-49da-96e9-617acd88f9b0" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2Fs4RNJ8HjLctwtdONb5aa%2Fimage.png?alt=media&amp;token=69409816-f317-47b3-b393-5ddd46c5e073" alt=""><figcaption></figcaption></figure>

### skynet\_module\_query

此处以logger 模块为例

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2Fq6E0uGmpxJQTKNuZ94AX%2Fimage.png?alt=media&amp;token=1b8be61a-59f7-4c9d-8802-3398daa4d1ac" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FRrJfJ1OoWIIsAkGp38hW%2Fimage.png?alt=media&amp;token=bb60244f-359f-44cc-ba16-1d21d6b3917c" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FpIQRE4J6HDclaqmBNckH%2Fimage.png?alt=media&amp;token=73519537-fdfb-4db5-88a2-6d39969f8a44" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FljC91hjlmIMsiXVy7ZYi%2Fimage.png?alt=media&amp;token=aaa9889f-520a-4fee-a688-a6cf5324f6ae" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FfHy8AyThhNonB229Vz61%2Fimage.png?alt=media&amp;token=021e677e-76f4-4140-a96a-ce5b5b0fcade" alt=""><figcaption></figcaption></figure>

在 query 时会在初始化的全局module 里寻找模块是否被加载, 此时还没有加载任何模块, 就会走到下一步的 \_try\_open 里去, 在 dlopen 打开动态链接库, 最后通过函数名获取对应模块的函数指针, 函数名分别为 <mark style="color:red;">**logger\_create, logger\_init, logger\_release, logger\_signal**</mark>

### skynet\_module\_instance\_create

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FlNXQYdqEAOMgPAf0agWX%2Fimage.png?alt=media&amp;token=ee8a0092-74ca-4e15-bcda-089dd291e982" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2F57Xvm7ubJpXbZb1c5zCC%2Fimage.png?alt=media&amp;token=b6ce1151-8731-4441-8d9c-12bf56f9a929" alt=""><figcaption></figcaption></figure>

这里已经加载了动态链接库, 就会调用 logger模块 logger\_create()  方法, 返回一个 logger的实例, 其他的service, harbor snlua 模块的启动都是这个流程

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FmfmHp1waZ18VF719IDbS%2Fimage.png?alt=media&amp;token=ebe2533c-d9fc-4525-b38e-d719133dad38" alt=""><figcaption></figcaption></figure>

之后创建 skynet\_context 对象, 把 mod 和 inst 与context 绑定, skynet\_handle\_register  ctx 向handle\_storage 上注册一个handle, skynet\_mq\_create 给ctx 创建自己的message\_queue

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2F8wqa0t9x0ZQGfcZxIhdZ%2Fimage.png?alt=media&amp;token=7ea92980-0ad3-4427-a013-e832f93e67fa" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2Fc3j4CeGvW9YHVHaZxcHK%2Fimage.png?alt=media&amp;token=6c04a851-c722-4159-827f-3ac691813d2a" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2Ffw2raXur5mdaMXeWqVq7%2Fimage.png?alt=media&amp;token=8cc46697-1ed5-40f1-9cfe-6762b653b8a9" alt=""><figcaption></figcaption></figure>

skynet\_module\_instance\_init  会调用logger 模块的 logger\_init 方法, 在配置文件里我们没有写日志文件的路径, 所以 inst->handle = stdout , 其日志会打印到stdout, 最后给 ctx 设置回调函数 logger\_cb, 到这里服务创建完成了, 最后把message\_queue 放入全局的 global\_queue 里

整个skynet\_context\_new 过程, 加载了mod, 创建mod 实例, 向全局的handle 注册一个 handle, 将 ctx 的 queue加入到全局队列

***

### bootstrap 流程

#### 1.bootstrap

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FNCOsOmElCpoBwYz8IJxF%2Fimage.png?alt=media&amp;token=820b034a-aae9-480f-b84d-359c632722b0" alt=""><figcaption></figcaption></figure>

bootstrap 里也是 skynet\_context\_new 方法, 而这里先对配置文件里的 bootstrap 字符串做了分割, 分割后name=snlua, args=bootstrap, 流程一样, 去 service\_snlua 模块里找对应的snlua\_create 和 snlua\_init 函数执行

#### 2. snlua init

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FO9aGugRjrXk6R77JD8ac%2Fimage.png?alt=media&amp;token=d3d49870-2f81-4c88-92f9-9e40100e7db4" alt=""><figcaption><p>snlua init</p></figcaption></figure>

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FYpcp6opnr08chG7HgXqu%2Fimage.png?alt=media&amp;token=b33df7c7-f137-4d6b-b5e8-d14627aef910" alt=""><figcaption><p>launch_cb</p></figcaption></figure>

snlua 在init 时, 做了两件比较重要的事, 第474行注册了callback 函数 launch\_cb, 然后在475行获取了自己的harbor\_id, 在478行给自己发送了一条msg(bootstrap), 这时会调用 launch\_cb

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FgedKkcWMLO70PgNSI7Wy%2Fimage.png?alt=media&amp;token=9cc3a76e-1ca1-4f82-9ac7-51b17a972b49" alt=""><figcaption><p>init cb</p></figcaption></figure>

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FgkAgjsowIVJz72SjB677%2Fimage.png?alt=media&amp;token=cead79f7-93b5-4442-8085-66f20095f626" alt=""><figcaption><p>init cb</p></figcaption></figure>

init\_cb前半段是加载lua 相应的环境, 423行添加trace 作为错误处理函数压入栈中, 428行加载 loader.lua 文件, 434行把args(bootstrap) 压入栈中, 435行执行 loader.lua 脚本, 把bootstrap 作为脚本的参数传入

#### 3. loader.lua

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FhR3mEeOFxRiK1UIylwwb%2Fimage.png?alt=media&amp;token=d62e9701-ef53-4d27-b4dc-9a3dd3013169" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FlOa3jxT2ZLFY0SN1U8kk%2Fimage.png?alt=media&amp;token=5711fff6-b2e0-4de0-8d44-08ef6f3c809e" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2F8axG4XMycYOWdbnQj6En%2Fimage.png?alt=media&amp;token=83df6da6-0787-417b-b5c2-915cdf8374ba" alt=""><figcaption></figcaption></figure>

在loader.lua 脚本中, 上半部分是做字符串操作, 我们这里传入的是bootstrap, service\_name 就是 bootstrap, 13行 loadfile() 之后, main = f 让main 指向了 bootstrap.lua; 之后寻找service\_path, 加载 preload(配置里没有), 最后执行 bootstrap.lua 脚本, 这里 select(2, table.unpack(args)), args只有一个参数bootstrap, 取args\[2] 为空, 所以就是无参执行 bootstrap.lua 脚本

#### 4. bootstrap.lua

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2Fkch9cqNNlsvoEJA9Ug2N%2Fimage.png?alt=media&amp;token=bce391ed-d32f-440b-871b-c0efd9da24d0" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1038370733-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsZbVV9N3S0zSZ23753et%2Fuploads%2FLD1iMFilzsbvUsK87EBh%2Fimage.png?alt=media&amp;token=b9050722-3cf0-436c-bf7f-5130600d9252" alt=""><figcaption></figcaption></figure>

这里面 skynet.launch, skynet.xxx 等方法在后续会讲述是如何与 c 代码交互, 先搞明白bootstrap.lua 在做什么

在bootstrap.lua 中, 首先启动了launcher.lua 脚本, 用 harbor\_id 区分单机模式还是集群模式, 单机模式下会走到 16 行启动 cdummy 服务, 之后启动 service\_mgr 和 datacenterd 服务

最后 pcall(skynet.newservice,skynet.getenv "start" or "main") 这一步, 就去执行我们的 main.lua 脚本, 至此bootstrap 就完成了
