解压后放到一个固定的位置
配置系统环境变量
如下配置完成
Protobuf核心的工具集是C++语言开发的,在官方的protoc编译器中并不支持Go语言。要想基于.proto文件生成相应的Go代码,需要安装相应的插件
安装 go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
syntax = "proto3"; //版本号
package go.micro.service.product; //包名
service Product { //定义的服务
rpc AddProduct(ProducInfo) returns (ResponseProduct){}
}
message ProductInfo { //消息格式
int64 id = 1;
string profuct_name = 2;
}
message ResponseProduct {
int64 product_id =1;
}
这是一个proto文件的基本格式
二、rpc原理
RPC 让远程调用就像本地调用一样,其调用过程可拆解为以下步骤。
① 服务调用方(client)以本地调用方式调用服务;
② client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
③ client stub找到服务地址,并将消息发送到服务端;
④ server 端接收到消息;
⑤ server stub收到消息后进行解码;
⑥ server stub根据解码结果调用本地的服务;
⑦ 本地服务执行并将结果返回给server stub;
⑧ server stub将返回结果打包成能够进行网络传输的消息体;
⑨ 按地址将消息发送至调用方;
⑩ client 端接收到消息;
⑪ client stub收到消息并进行解码;
⑫ 调用方得到最终结果。
使用RPC框架的目标是只需要关心第1步和最后1步,中间的其他步骤统统封装起来,让使用者无需关心。例如社区中各式RPC框架(grpc、thrift等)就是为了让RPC调用更方便。
案例
client端代码
package main
import (
"fmt"
"log"
"net/rpc"
)
func main() {
client, err := rpc.Dial("tcp", ":1234")
if err != nil {
log.Fatal("dialing:", err)
}
var replay string
err = client.Call("HelloService.Hello", "cx", &replay)
if err != nil {
log.Fatal(err)
}
//打印调用响应
fmt.Println(replay)
}
server端代码
package main
import (
"fmt"
"log"
"net"
"net/rpc"
)
type HelloService struct {
}
//request 请求
//response 相应
//request --> name
//response < --
func (s *HelloService) Hello(request string, response *string) error {
*response = fmt.Sprintf("hello,%s", request)
return nil
}
//main里编写server
func main() {
//把rpc对外暴露的对象注册到rpc框架内部
rpc.RegisterName("HelloService", &HelloService{})
//准备socket
//建立一个唯一的TCP链接
listener, err := net.Listen("tcp", "localhost:1234")
if err != nil {
log.Fatal("ListenTCP error:", err)
}
//获取链接
for {
coon, err := listener.Accept()
if err != nil {
panic(err)
}
//每个客户端单独建立一个routine来处理
go rpc.ServeConn(coon)
}
}