0.protoc文件编写编译
a. protoc协议中消息字段定义(统一使用驼峰格式命名,单词之间不要使用下换线连接),使得生成的消息协议,在rpc api编解码和 json编解码中,json字段名是一样,这样调用方,使用发送kafka消息,或者调用go-micro API中生成json数据时候,只要写一套json就可以了
b.枚举中的值不用加前缀,编译的时候自动会加,如OWNER在pb.go中会定义成: MemberType_OWNER(区分大小写的)
c. import其他proto的时候,2个文件呢中的pakcet 名字要一样,如package protocol;
enum MemberType {
BEGIN = 0;
OWNER = 1; //群主
ADMIN = 2; //管理员
NORMAL = 3; //普通成员
}
编译(可以直接下载protoc文件的二进制文件):
protoc --go_out=. msg.proto
根据.proto文件生成.pb.go,在gopath的src目录下,protoc --proto_path=./ --go_out=./ goim/libs/model/msg.proto
1.net/rpc 服务端
线程模型
每个新链接使用一个协程处理 , 看源码net/rpc/server.go
// Accept accepts connections on the listener and serves requests
// for each incoming connection. Accept blocks until the listener
// returns a non-nil error. The caller typically invokes Accept in a
// go statement.
func (server *Server) Accept(lis net.Listener) {
for {
conn, err := lis.Accept()
if err != nil {
log.Print("rpc.Serve: accept:", err.Error())
return
}
go server.ServeConn(conn)
}
}
同一个链接的每个函数调用,启动一个协程处理
// ServeCodec is like ServeConn but uses the specified codec to
// decode requests and encode responses.
func (server *Server) ServeCodec(codec ServerCodec) {
sending := new(sync.Mutex)
wg := new(sync.WaitGroup)
for {
service, mtype, req, argv, replyv, keepReading, err := server.readRequest(codec)
if err != nil {
if debugLog && err != io.EOF {
log.Println("rpc:", err)
}
if !keepReading {
break
}
// send a response if we actually managed to read a header.
if req != nil {
server.sendResponse(sending, req, invalidRequest, codec, err.Error())
server.freeRequest(req)
}
continue
}
wg.Add(1)
go service.call(server, sending, wg, mtype, req, argv, replyv, codec)
}
// We've seen that there are no more requests.
// Wait for responses to be sent before closing codec.
wg.Wait()
codec.Close()
}
2. 客户端模型
连接成功后创建了一个 go input(),作为接收 "回调" 协程,接收到数据后,根据发送的seq id,找到对应的调用Call,然后调用Call.done(), 阻塞的rpc调用,就可以返回了,否则rpc调用一直阻塞着
不具备断链重连功能,没有底层实现心跳
3.rpc/net提供一个默认的 var DefaultServer = NewServer(), 可以Register多个对象
rpc.Register(&logicRpc)