分类 编程 中的文章

Go-libp2p三 | relay例子

我想做什么

chat和echo两个例子,说明了两个节点之间的通信需要两节点在同一个局域网内,或者有一个节点有公网。 如果我两个节点分别在两个NAT下面, 都在各自的局域网内,则需要有一个中继服务,这个服务做如下两件事:

……

阅读全文

Go-libp2p二 | echo例子

go-libp2p的echo例子分析

进入目录go-libp2p/examples/echo/, 编译 go build

先看README.md, 可以了解到使用echo的方式: 终端B

$ ./echo -l 3001
2021/10/28 11:25:33 I am /ip4/127.0.0.1/tcp/3001/p2p/QmTu8sxDi3fSjz9ZMvkAj3qA9YAoGskroEnyLz2ZvfTBhX
2021/10/28 11:25:33 listening for connections
2021/10/28 11:25:33 Now run "./echo -l 3002 -d /ip4/127.0.0.1/tcp/3001/p2p/QmTu8sxDi3fSjz9ZMvkAj3qA9YAoGskroEnyLz2ZvfTBhX" on a different terminal

2021/10/28 11:25:59 listener received new stream
2021/10/28 11:25:59 read: Hello, world!

在另外一个终端输A入:

……

阅读全文

Go-libp2p一 | chat例子

代码下载

git clone https://github.com/libp2p/go-libp2p.git

chat实例分析

进入目录go-libp2p/examples/chat/, 编译 go build 先看README.md, 可以了解到使用chat的方式

  1. 在节点 B
$ ./chat -sp 3001
2021/10/28 11:01:25 Run './chat -d /ip4/127.0.0.1/tcp/3001/p2p/QmXgEXt4CiqmVmDhPPQnyVkoj3Bsx3Nggq57PPsk5tLNTs' on another console.
2021/10/28 11:01:25 You can replace 127.0.0.1 with public IP as well.
2021/10/28 11:01:25 Waiting for incoming connection
2021/10/28 11:01:25 
2021/10/28 11:03:03 Got a new stream!
> hello
  1. 在节点 A, 如果B有公网IP,则把127.0.0.1替换成B的公网IP
$ ./chat -d /ip4/127.0.0.1/tcp/3001/p2p/QmXgEXt4CiqmVmDhPPQnyVkoj3Bsx3Nggq57PPsk5tLNTs
2021/10/28 11:03:03 This node's multiaddresses:
2021/10/28 11:03:03  - /ip4/172.16.3.205/tcp/53084
2021/10/28 11:03:03  - /ip4/127.0.0.1/tcp/53084
2021/10/28 11:03:03 
2021/10/28 11:03:03 Established connection to destination
> hello

作为被连接方B

先看代码:

……

阅读全文

Skynet源码赏析四 | 消息调度

服务间消息流转

发送消息

数据结构message_queue *q是次级消息队列,每个服务都有与之绑定的唯一一个次级消息队列。当我们在lua层,调用skynet.send(...), 或者调用skynet.call(...)函数发送消息,其实调用的都是c.send(...),实际上调用的是c接口:

……

阅读全文

Skynet源码赏析三 | 服务启动

skynet启动一个C服务

查看怎么启动C服务的最好的办法是打断点,看源码。

启动logger日志服务

我拿日志服务来举例子,怎么启动日志服务的呢?

  1. 传参数name = "logger", param = nullstruct skynet_context *ctx = skynet_context_new(config->logservice, config->logger);;
  2. 从modules服务模块中取出名字为 logger的服务, struct skynet_module * result = _query(name);;
  3. 如果找不到则从cpath目录中找对应的.so文件,打开服务,并且存储到modules模块中。使用的函数是static void * _try_open(struct modules *m, const char * name);
  4. 创建服务实例m->create(),放到上下文skynet_contextinst中;
  5. skynet_context放到skynet_context list中, skynet_handle_register(ctx);;
  6. 创建logger服务对应的次级消息队列struct message_queue *queue,并且把消息队列push到全局消息队列中skynet_mq_create(ctx->handle);skynet_globalmq_push(queue);;
  7. 服务实例初始化m->init(),int r = skynet_module_instance_init(mod, inst, ctx, param);

总结下来,启动一个服务的过程就是,1.获取服务;2.创建服务实例;3.创建服务对应的上下文,并且把上下文放到skynet_context list管理模块中;4.绑定次级消息队列与对应的服务;5.服务初始化; 这五步过程。

……

阅读全文

Skynet源码赏析二 | 基础数据结构

module管理模块

我们所写的C服务编译成.so文件后放在cpath变量路径下,程序会加载路径cpath = root.."cservice/?.so"下的.so文件,通过static void * _try_open(struct modules *m, const char * name)函数第一次打开,然后被加载到全局变量static struct modules * M中。

……

阅读全文

Skynet源码赏析一 | 启动初始化的过程

入口文件

skynet_main.c

加载配置

struct skynet_config config;
config.thread =  optint("thread",8);
config.module_path = optstring("cpath","./cservice/?.so");
config.harbor = optint("harbor", 1);
config.bootstrap = optstring("bootstrap","snlua bootstrap");
config.daemon = optstring("daemon", NULL);
config.logger = optstring("logger", NULL);
config.logservice = optstring("logservice", "logger");
config.profile = optboolean("profile", 1);

从上述代码可以看到,配置都已经加载到变量struct skynet_config config;中了。

初始化

  1. 初始化skynet_context管理模块, skynet_handle_init(config->harbor);;
  2. 初始化static struct global_queue *Q消息队列, skynet_mq_init();;
  3. 初始化static struct modules * M管理模块, skynet_module_init(config->module_path);;
  4. 初始化定时器, skynet_timer_init();;

启动C服务

  1. 启动logger日志服务, struct skynet_context *ctx = skynet_context_new(config->logservice, config->logger);;
  2. 启动 snlua服务, ``;
  3. 通过snlua服务启动boostrap服务, bootstrap(ctx, config->bootstrap);;
  4. 启动线程:
  • 监听线程,检测线程是否阻塞。 create_thread(&pid[0], thread_monitor, m);;
  • 启动定时器线程。create_thread(&pid[1], thread_timer, m);;
  • 启动socket线程。create_thread(&pid[2], thread_socket, m);
  • 启动工作线程,用于lua服务消息的调度。create_thread(&pid[i+3], thread_worker, &wp[i]);;

启动lua服务

默认启动的lua服务,在boostrap.lua文件中可以看到都是通过snlua服务启动的。

……

阅读全文

FPS游戏 | 实现移动功能

三种实现FPS Controller的区别

  1. Transform Translate 允许移动物理,但无物理碰撞
  2. Rigid body + Capsule Collider 符合物理学 不会鬼穿墙 无法滞空运动 可与Physics Object 交互
  3. Charactor Controller 不会鬼穿墙 提供的API相对多 无法与Physic objects互动 可以滞空运动(太空人) 提供多种运动效果例如 slopes steps 等

Rigid body + Capsule Collider

控制摄像头旋转 FPMouseLook.cs 跟main camera 绑定

……

阅读全文

免费Music

介绍一个可以免费听音乐的方法

环境

  • docker
  • mac

安装

$ docker run -d -p 264:264 -p 9000:9000 -v $dir_name:/var/www/html/cache --name music oldiy/music-player-docker

$dir_name 是 你自己宿主机的目录。可以自定义

访问:127.0.0.1:264

就可以放心使用, 同事推荐的,贼好用。

……

阅读全文