Go-libp2p三 | relay例子
我想做什么
chat和echo两个例子,说明了两个节点之间的通信需要两节点在同一个局域网内,或者有一个节点有公网。
如果我两个节点分别在两个NAT下面, 都在各自的局域网内,则需要有一个中继服务,这个服务做如下两件事:
chat和echo两个例子,说明了两个节点之间的通信需要两节点在同一个局域网内,或者有一个节点有公网。
如果我两个节点分别在两个NAT下面, 都在各自的局域网内,则需要有一个中继服务,这个服务做如下两件事:
进入目录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入:
……git clone https://github.com/libp2p/go-libp2p.git
进入目录go-libp2p/examples/chat/, 编译 go build
先看README.md, 可以了解到使用chat的方式
$ ./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
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
先看代码:
……数据结构message_queue *q是次级消息队列,每个服务都有与之绑定的唯一一个次级消息队列。当我们在lua层,调用skynet.send(...), 或者调用skynet.call(...)函数发送消息,其实调用的都是c.send(...),实际上调用的是c接口:
查看怎么启动C服务的最好的办法是打断点,看源码。
我拿日志服务来举例子,怎么启动日志服务的呢?
name = "logger", param = null, struct skynet_context *ctx = skynet_context_new(config->logservice, config->logger);;logger的服务, struct skynet_module * result = _query(name);;static void * _try_open(struct modules *m, const char * name);m->create(),放到上下文skynet_context的inst中;skynet_context放到skynet_context list中, skynet_handle_register(ctx);;struct message_queue *queue,并且把消息队列push到全局消息队列中skynet_mq_create(ctx->handle);,skynet_globalmq_push(queue);;m->init(),int r = skynet_module_instance_init(mod, inst, ctx, param);总结下来,启动一个服务的过程就是,1.获取服务;2.创建服务实例;3.创建服务对应的上下文,并且把上下文放到skynet_context list管理模块中;4.绑定次级消息队列与对应的服务;5.服务初始化; 这五步过程。
我们所写的C服务编译成.so文件后放在cpath变量路径下,程序会加载路径cpath = root.."cservice/?.so"下的.so文件,通过static void * _try_open(struct modules *m, const char * name)函数第一次打开,然后被加载到全局变量static struct modules * M中。
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;中了。
skynet_context管理模块, skynet_handle_init(config->harbor);;static struct global_queue *Q消息队列, skynet_mq_init();;static struct modules * M管理模块, skynet_module_init(config->module_path);;skynet_timer_init();;logger日志服务, struct skynet_context *ctx = skynet_context_new(config->logservice, config->logger);;snlua服务, ``;snlua服务启动boostrap服务, bootstrap(ctx, config->bootstrap);;create_thread(&pid[0], thread_monitor, m);;create_thread(&pid[1], thread_timer, m);;socket线程。create_thread(&pid[2], thread_socket, m);create_thread(&pid[i+3], thread_worker, &wp[i]);;默认启动的lua服务,在boostrap.lua文件中可以看到都是通过snlua服务启动的。
今天用Golang写一个调用外部shell脚本的程序,使用 exec.Command方法,这段脚本代码中包含了一个后台任务语句。 结果发生了一个问题:cmd.Output 始终不会返回,一直挂起。导致我的Go程序也挂起了。
控制摄像头旋转 FPMouseLook.cs 跟main camera 绑定
……环境
$ 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
就可以放心使用, 同事推荐的,贼好用。
……