(1)
巼吥1/3 19:59:20
pbc 编码完有没接口获取msg的长度
云风 20:14:36
pbc_slice 里的长度就是
巼吥1/3 20:41:39
恩 看到了 不过在skynet里面lua里面local buffer = protobuf.encode("tutorial.Person", person)
-- print(buffer)
skynet.ret(buffer,36)
(2)
394463337 20:46:37有个小问题,新版本的代码里向client发送消息时,为什么强制是TEXT类型的协议啊
云风 20:47:06
发出 skynet 的消息其实是没有协议的
云风 20:47:25
type 那个信息会丢掉
但是不是有pack和unpack么
394463337 20:47:35
那这样pack不就没用了
云风 20:48:00
client 本身一般都根据项目需要自己写的
云风 20:48:25
我们的项目就封装了一个 protobuffer 协议的 client
(3)
巼吥1/3 20:48:57pbc 和skynet要怎么结合 还没搞懂 send的时候要msg 和size 可是pbc里面出来的好像不行
云风 20:49:14
skynet client 本身是一个内部 serivce, 它可以拿到 type, session id, data 等等
云风 20:49:20
然后打包发出去
394463337 20:50:05
对,就是向这个内部client-service发送的时候也是无类型的么
云风 20:51:19
static struct pack_proto *PB = NULL;
#define MAX_HEADER 64
#define MAX_SEND_BUF 65535
struct client {
int id;
};
/*
老的游戏协议包, 包协议用 protobuffer
package proto;
message Pack
{
optional int32 session = 1;
optional int32 type = 2;
optional bytes data = 3;
}
当 type > 0 时, 表示是一个请求包. session 为一个 >0 的正数.
当 type == 0 时, 表示是一个回应包. session 为一个 >0 的正数, 对应之前发过来的请求包中的 session.
转换到新内部协议:
msg 的前两个字节必须是 type 字段. 之后是 protobuffer 包
*/
static int
_cb(struct skynet_context * context, void * ud, int stype, int session, uint32_t source, const void * msg, size_t sz) {
assert(sz <= 65535);
struct client * c = (struct client*) ud;
size_t buflen = sz + MAX_HEADER;
uint8_t *buffer = malloc(buflen);
struct ejoy_pack package;
uint16_t type = 0;
package.session = session;
if (stype == PTYPE_RESPONSE) {
package.type = 0;
package.data.buffer = (void *)msg;
package.data.len = sz;
} else {
assert(stype == PTYPE_EJOY_PACKAGE);
const uint8_t *header = msg;
type = header[0] << 8 | header[1];
package.type = type;
package.data.buffer = (void *)((uintptr_t)msg + sizeof(type));
package.data.len = sz - sizeof(type);
}
struct pbc_slice slice;
slice.buffer = buffer + 2;
slice.len = buflen - 2;
int err = pbc_pattern_pack(PB->pack, &package , &slice);
assert(err>=0);
assert(slice.len <= 65535);
buffer[0] = (slice.len >> 8) & 0xff;
buffer[1] = slice.len & 0xff;
skynet_socket_send(context, c->id, buffer, slice.len + 2);
return 0;
}
云风 20:51:27
这是我们一个项目的 client
394463337 20:52:44
哦,知道了,谢谢啊,client-service都是自己来定制的喽
云风 20:53:19
我们把一个 skynet 内部的消息,附加上 session 然后按 pb 打包
云风 20:53:54
这里我们就限制发送给 client 的 type 一定是 PTYPE_EJOY_PACKAGE
云风 20:54:10
如果不是,一定是写错了,也无法打包
394463337 20:54:18嗯,明白了
394463337 20:54:18
if (type == PTYPE_RESERVED_ERROR) {
// todo: tell client the session is broken
return 0;
}
if (type == PTYPE_RESPONSE) {
// todo: response to client with session, session may be packed into package
} else {
printf("client %d\n",type);
assert(type == PTYPE_TEXT);
// todo: support other protocol
}
// todo: design
394463337 20:54:35
这个最新版的代码,我是用的时候感到奇怪
巼吥1/3 20:54:41
哦 那在skynet的lua层要怎么调用
394463337 20:54:58
明白了现在
394463337 20:55:23
skynet用lua时是要先注册协议的
394463337 20:55:33
一个lua service先注册协议
394463337 20:56:05
像TEXT是属于通用的一种,打解包方式是定义在你注册的protocol里的pack-unpack里的
(4)
云风 20:56:2
function ejoy.dispatch(session, address, type,msg,sz)
local info = skynet.trace()local trace_tmp = {}
trace_cache[info] = trace_tmp
assert(type>0)
local message = pbu.lookup(type)
local data = pb.decode(message.input , msg, sz)
trace_tmp.message = message
trace_tmp.data = data
local routine = assert(message_table[message.name], message.name)
routine(data, address , session)
end
function ejoy.dispatch_client(session, address , msg, sz, type)
return ejoy.dispatch(session, address, type, msg, sz)
end
skynet.register_protocol {
name = "ejoy",
id = 14,
pack = function (...) return ... end,
unpack = function(...)
return ejoypack.extract_type(...)
end,
dispatch = ejoy.dispatch,
}
skynet.register_protocol {
name = "ejoy_client",
id = 15,
unpack = function (...) return ... end,
dispatch = ejoy.dispatch_client,
}
394463337 20:56:27
调用的时候还是skynet.send或skynet.call,参数会经过你注册的pack出去
云风 20:56:41
我们 server 收到 client 发来的消息这样处理的
云风 20:58:47
主要是这一行
unpack = function(...)
return ejoypack.extract_type(...)
end,
云风 21:00:00
对应前面的
const uint8_t *header = msg;
type = header[0] << 8 | header[1];
package.type = type;
云风 21:00:46
我们 C/ S 通讯额外有一个整数表示协议号的,就是这个 type, 和 skynet 的 type 是两个东西
(5)
394463337 21:00:53云大,skynet里检测到断线是怎么处理的啊,我目前是watchdog检测到通知agent来做清理的,但是我看你的BLOG也提到,需要一种优雅的方式来处理么
云风 21:01:33
断线是在 gate 里检测到,发给 watchdog 后,最终转化为游戏内部协议的
云风 21:01:54
就是 socket 断了后,最终处理的代码会收到一条明确的协议
394463337 21:02:07
嗯,这个我理解的
云风 21:02:55
断线我们现在等同于玩家主动退出,行为是一致的
(6)
云风 21:03:46
接上面那个, 我们设计的比较早,方法未必好. 当时区分了 ejoy 和 ejoy_client
云风 21:03:59
ejoy 指一种在 skynet 内部流通的协议
云风 21:04:18
ejoy_client 指同样的协议,但需要经过打包变成一个数据块
云风 21:04:57
因为 skynet 内部的协议 是 session type data 的复合体,但和 client 交流只能有一个数据块