云风的skynet,定义为一个游戏服务器框架,用c + lua基于Actor模型实现。代码极其精简,c部分的代码只有三千行左右。
     整个skynet框架要解决的核心问题是:把一个消息(数据包)从一个服务(Actor)发送给另一个服务(Actor),并接收其返回。也就是在同一进程内(作者也强调并非只限于同一进程,因为可能会有集群间的通讯)的一个服务通过类似rpc之类的调用同一进程内的另外一个服务,并接收处理结果。而skynet就是处理这些服务间发送数据包的规则和正确性。
     skynet的核心层全部是c来实现。
     当系统启动的时候,会得到一个提前分配好的节点id,我们称之为harbor id,这个id是集群用的,一个集群内可以启动很多个skynet节点,每个节点都会分配到唯一的id。
     一个节点(即一个进程)内有很多个服务,服务可以狭义地暂且理解为功能模块。
     当初始化一个服务的时候,会生成一个skynet_context来作为服务的实例;一个唯一(即使是在集群里也是唯一)的服务handle,即服务的唯一id,用来识别服务;一个消息队列message_queue;还要向框架注册一个callback,当服务收到有发送来的消息时,通过这个方法传入。
     初始化一个服务的代码如下:
 
struct skynet_context *
skynet_context_new(const char * name, const char *param) {
// 装载模块
struct skynet_module * mod = skynet_module_query(name); if (mod == NULL)
return NULL; void *inst = skynet_module_instance_create(mod);
if (inst == NULL)
return NULL;
// 初始化skynet_context实例
struct skynet_context * ctx = skynet_malloc(sizeof(*ctx));
CHECKCALLING_INIT(ctx) ctx->mod = mod;
ctx->instance = inst;
ctx->ref = ;
ctx->cb = NULL;
ctx->cb_ud = NULL;
ctx->session_id = ;
ctx->logfile = NULL; ctx->init = false;
ctx->endless = false;
// 初始化服务handle
// Should set to 0 first to avoid skynet_handle_retireall get an uninitialized handle
ctx->handle = ;
ctx->handle = skynet_handle_register(ctx);
// 初始化消息队列
struct message_queue * queue = ctx->queue = skynet_mq_create(ctx->handle);
// init function maybe use ctx->handle, so it must init at last
context_inc(); CHECKCALLING_BEGIN(ctx)
int r = skynet_module_instance_init(mod, inst, ctx, param);
CHECKCALLING_END(ctx)
if (r == ) {
struct skynet_context * ret = skynet_context_release(ctx);
if (ret) {
ctx->init = true;
}
skynet_globalmq_push(queue);
if (ret) {
skynet_error(ret, "LAUNCH %s %s", name, param ? param : "");
}
return ret;
} else {
skynet_error(ctx, "FAILED launch %s", name);
uint32_t handle = ctx->handle;
skynet_context_release(ctx);
skynet_handle_retire(handle);
struct drop_t d = { handle };
skynet_mq_release(queue, drop_message, &d);
return NULL;
}
}

在skynet_handle_register方法中生成一个服务handle,handle是一个32位的整数,在生成handle的时候,是把该节点的harbor id写到了handle的高8位里面,所以一个服务的handle,就可以知道这个服务是哪个节点的。

          s->handle_index = handle + ;
rwlock_wunlock(&s->lock);
handle |= s->harbor;
return handle;
所以说,harbor id最高也只有256个,也就意味着skynet集群最多只能有256个节点,而一个节点里最多也只能有24位个服务,即1.6M个。因为一个handle是32位的整数,高8位用来存储harbor id,只有低的24位用来分配给本节点的handle。
     消息队列message_queue是用来存储发送给该服务的消息的。所有发送给该服务的消息,都要先压到该服务的消息队列中。
 
     服务启动起来了,来看看数据包是如何从一个服务发送给另一个服务的。
     来看看 skynet_send 和 callback 函数的定义:
int skynet_send(
struct skynet_context * context,
uint32_t source,
uint32_t destination,
int type,
int session,
void * msg,
size_t sz
); typedef int (*skynet_cb)(
struct skynet_context * context,
void *ud,
int type,
int session,
uint32_t source ,
const void * msg,
size_t sz
);
source和destination分别是发送方和接收方的handle。
type是发送方和接收方处理数据包的协议
session识别本次调用的口令,发送方发送一个消息后,保留该session,以便收到回应数据包时,能识别出是哪一次调用。
msg/sz是数据包的内容和长度,成对使用
 
skynet 的消息调度

 
Skynet 维护了两级消息队列。
 
每个服务实体有一个私有的消息队列,队列中是一个个发送给它的消息。消息由四部分构成:
 
struct skynet_message {
    uint32_t source;
    int session;
    void * data;
    size_t sz;
};
向一个服务发送一个消息,就是把这样一个消息体压入这个服务的私有消息队列中。这个结构的值复制进消息队列的,但消息内容本身不做复制。
 
Skynet 维护了一个全局消息队列,里面放的是诸个不为空的次级消息队列。
 
在 Skynet 启动时,建立了若干工作线程(数量可配置),它们不断的从主消息列队中取出一个次级消息队列来,再从次级队列中取去一条消息,调用对应的服务的 callback 函数进行出来。为了调用公平,一次仅处理一条消息,而不是耗净所有消息(虽然那样的局部效率更高,因为减少了查询服务实体的次数,以及主消息队列进出的次数),这样可以保证没有服务会被饿死。
 
这样,skynet就实现了把一个消息(数据包)从一个服务发送给另一个服务。
 

参考:Skynet 设计综述

 
 
 

skynet是什么的更多相关文章

  1. skynet的协程

    之前对skynet的印象,主要是来自于我对golang的理解,对gevent开发的经验,以及云风的blog.对于底层的代码,并没有仔细去阅读过.最近在实现业务系统的时候,发现有同事在同一个函数里做了一 ...

  2. Skynet Pomelo Erlang Elixir 的认识

    1.skynet pomelo(node.js) elixir(erlang) 周末研究总结 手游这两年发展来看,感觉对实时性要求越来越高,有同事在研究Elixir开发,google得知这东西是基于e ...

  3. 转:云风skynet服务端框架研究

    转:  http://forthxu.com/blog/skynet.html skynet是云风编写的服务端底层管理框架,底层由C编写,配套lua作为脚本使用,可换python等其他脚本语言.sky ...

  4. skynet启动过程_bootstrap

    这遍摘自skynet 的wiki skynet 由一个或多个进程构成,每个进程被称为一个 skynet 节点.本文描述了 skynet 节点的启动流程. skynet 节点通过运行 skynet 主程 ...

  5. skynet启动过程_1

    skynet的启动时需带个配置文件,这个文件其实是作为lua全局变量用的,见 int main(int argc, char *argv[]) { const char * config_file = ...

  6. skynet网络库socket-server

    最近在读大神云风的开源服务器架构skynet,其中的网络库,云风已经单独开来,可以独立使用. 开源地址: https://github.com/cloudwu/socket-server 网络库已经封 ...

  7. Skynet:特性收集

    基于云风的 blog,收集 skynet 的特性以便将来在代码中一一验证. “ ... ” 部分节选自云风的 BLOG. 1. 基于 Erlang-Actor 模式的 C 实现 “把一个符合规范的 C ...

  8. skynet的流程1

    logpath = "."harbor = 1address = "127.0.0.1:2526"master = "127.0.0.1:2013&q ...

  9. skynet newservice API参考

    local skynet = require("skynet") skynet.start(start_func) c服务snlua启动后执行的第一个lua文件里面的主逻辑必定是s ...

随机推荐

  1. vijos p1193 扫雷

      描述 相信大家都玩过扫雷的游戏.那是在一个n*n的矩阵里面有一些雷,要你根据一些信息找出雷来.万圣节到了,“余”任过流行起了一种简单的扫雷游戏,这个游戏规则和扫雷一样,如果某个格子没有雷,那么它里 ...

  2. 终极秘籍教你怎么找回被盗iPhone 查询ICCID

    iPhone不慎丢失后怎么办?普通青年:立刻报警,基本没用.文艺青年:用Find my iPhone查找位置.但那只是个大概位置,iPhone关机后更是没戏,接着是用iCloud锁定手机,发送警告信息 ...

  3. VS2005 工程在win7下使用管理员权限运行

    想关资料 http://stackoverflow.com/questions/13030492/set-administrator-privilege-for-my-c-application-in ...

  4. RESTLET开发实例(三)基于spring的REST服务

    http://www.lifeba.org/arch/restlet_spring_3.html 前面两篇文章,我们介绍了基于JAX-RS的REST服务以及Application的Rest服务.这里将 ...

  5. Monkey的简单自动化

    手机测试都逃避不了Monkey,但每次都是手动跑Monkey,自己导出包来,一条条的手动输入命令. 现在轮到我去执行这些任务,觉得很是繁琐,于是写了这个脚本,自动读取导出的包名,一键回车搞定. 代码如 ...

  6. 四元数(Quaternion)详细讲解以及在图形图像编程中的使用

    关于四元数介绍可以直接看wiki,写的很详细了. 四元数的基本运算:http://www.linuxgraphics.cn/opengl/opengl_quaternion.html,代码有些问题. ...

  7. Bzoj 1562: [NOI2009]变换序列 匈牙利算法,二分图匹配

    题目: http://cojs.tk/cogs/problem/problem.php?pid=409 409. [NOI2009]变换序列 ★★☆   输入文件:transform.in   输出文 ...

  8. Scala学习笔记(一)数据类型

    .类型参数化数组 val arrayString = Array[String](2); arrayString (0)="Hello"; arrayString (1)=&quo ...

  9. 【Java基础】static关键字的理解

    修饰范围: 可以修饰成员变量和成员方法.静态的特点: A:随着类的加载而加载 B:优先于对象存在 C:被类的所有对象共享 这其实也是我们判断该不该使用静态的依据. 举例:饮水机和水杯的问题思考可通过类 ...

  10. POJ2752 - Seek the Name, Seek the Fame(KMP)

    题目大意 给定一个字符串S,求出所有既是S的前缀又是S的后缀的子串长度 题解 从末尾位置倒推,经过的失配函数值就是题目要求求的 代码: #include <iostream> #inclu ...