go rpc

运用go标准库写一个rpc例子

服务端

go 复制代码
package main

import (
	"fmt"
	"net"
	"net/rpc"
)

//对象
type Hello struct {
}
//对象方法
func (h *Hello) HelloWorld(name string, resp *string) error {
	*resp = name + "你好"
	return nil
}

func main() {
	//1. 注册RPC服务,绑定对象方法
	err := rpc.RegisterName("hello", new(Hello))
	if err != nil {
		fmt.Println("rpc RegisterName error")
		return
	}

	//2. 初始化监听器
	listener, err := net.Listen("tcp", "127.0.0.1:8800")
	if err != nil {
		fmt.Println("net Listen error")
		return
	}
	defer listener.Close()
	
	//3.建立连接
	conn, err := listener.Accept()
	if err != nil {
		fmt.Println("listener Accept error")
		return
	}
	defer conn.Close()
	
	//4.将连接绑定rpc服务
	rpc.ServeConn(conn)
}

注意绑定的对象方法,必须有两个参数,第二个参数必须是"指针类型"为传出参数。方法只有一个error类型的返回值。

客户端

go 复制代码
package main

import (
	"fmt"
	"net/rpc"
)

func main() {
	//建立连接
	conn, err := rpc.Dial("tcp", "127.0.0.1:8800")
	if err != nil {
		fmt.Println("rpc Dial error")
		return
	}
	defer conn.Close()
	//调用远程函数
	var resp string
	err = conn.Call("hello.HelloWorld", "李白", &resp)
	if err != nil {
		fmt.Println("conn Call error")
		return
	}
	fmt.Println(resp)
}

注意:上面代码中rpc的远程函数调用采用的是golang中特有的序列化包gob,其他语音不能解析。所以,要进行不同语言之间的rpc通信可以采用通用的序列化方式,如json,protobuf

然后,在实际运用中都会对服务端和客户端的再进行封装:

protobuf添加rpc服务

此时使用的protobuf编译指令,将定义好的proto规则和rpc服务生成go代码,需要用到的是grpc

bash 复制代码
protoc --go_out=. *.proto
protoc --go-grpc_out=. *.proto

举例:

定义proto文件,然后用上面两个命令生成go代码

go 复制代码
syntax="proto3";

package pb;

//option go_package = "path;name"; path 表示生成的go文件的存放地址,会自动生成目录的
// name 表示生成的go文件所属的包名
option go_package=".;pb";

message HelloRequest {
  string requestName = 1;
}

message HelloResponse {
  string responseMsg = 1;
}

service Hello{
  rpc SayHello(HelloRequest) returns (HelloResponse);
}

服务端:

go 复制代码
package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"net"
	"rpc_day01/pb"
)

type My struct {
	pb.UnimplementedHelloServer //必须嵌套这个
}

func (m *My) SayHello(c context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {
	var resp pb.HelloResponse
	resp.ResponseMsg = req.RequestName + " hello !!"
	return &resp, nil
}

func main() {
	//1 初始化一个gpc对象
	grpcServer := grpc.NewServer()
	//2 注册服务
	pb.RegisterHelloServer(grpcServer, &My{})

	//3 设置监听,指定IP
	listener, err := net.Listen("tcp", "127.0.0.1:8801")
	if err != nil {
		fmt.Println("net Listen error")
		return
	}
	defer listener.Close()

	//4 启动服务
	grpcServer.Serve(listener)
}

客户端:

go 复制代码
package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"log"
	"rpc_day01/pb"
)

func main() {
	//连接grpc服务(无加密)
	conn, err := grpc.Dial("127.0.0.1:8801", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	//初始化grpc客户端
	grpcClient := pb.NewHelloClient(conn)
	resp, err := grpcClient.SayHello(context.Background(), &pb.HelloRequest{RequestName: "李白"})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(resp.ResponseMsg)
}
相关推荐
apocelipes1 天前
常用编程语言和库的正则表达式性能对比
c语言·c++·python·性能优化·golang·开发工具和环境
AsulTop6 天前
精简版 OpenWrt/LEDE uhttpd/rpc/mod-rpc/ Ubus Json-RPC 从0修复直到可用
rpc·路由器·openwrt·lede·uhttpd·ubus修复
何以解忧,唯有..16 天前
Go语言循环语句详解:for、range与循环控制
开发语言·算法·golang
小胖xiaopangss16 天前
BRpc使用
c++·rpc
踏着七彩祥云的小丑16 天前
Go学习第9天:并发编程 + 文件操作 + 正则表达式
学习·golang·正则表达式·go
JCGKS16 天前
Go `init` 函数:包初始化顺序到底是怎样的
golang·init·init执行顺序
何以解忧,唯有..17 天前
Go语言中的const:常量声明与iota枚举详解
java·开发语言·golang
zhuzicc17 天前
Dubbo @Autowired 注入同模块接口,到底走的是本地调用还是 RPC?源码给你答案(Dubbo @Service注解的双重注册机制)
rpc·autowired·dubbo·依赖注入·java面试·spring ioc·dubbo源码分析
geovindu17 天前
go: Reactor Pattern
开发语言·后端·设计模式·golang·反应器模式
記億揺晃着的那天17 天前
Java 调用外部 Go 程序的实践:ProcessBuilder 在生产环境中的应用
java·golang·processbuilder