Go RPC

Go RPC

Go语言的标准库RPC实现:net/rpc

  • Socketa编程

  • 序列化(json/xml/…)

请添加图片描述
请添加图片描述

RPC Server

下面是HelloService,提供了一个Hello方法

type HelloService struct { }
//Hello的逻辑就是将对方发送的消息前面添加一个He11o然后返还给对方
//由于我们是一个rpc服务,因此参数上面还是有约束: 
//第一个参数是请求
//第二个参数是响应
//可以类比Http handler
func (p *HelloSepvice) Hello(request string,reply *string)error{
       *reply = "hello:" + request
       return nil
 }
func main(){
//把我们的对象注册成一个rpc的receiver
//其中rpc.Register函数调用会将对象类型中所有满足RPC规则的对象方法注册为RPC函数, 
 //所有注册的方法会放在"HelloService"服务空间之下 rpc.RegisterName(HelloService",new(HelloService))
//然后我们建立一个唯一的TCP链接,  常见的socket编程的技巧
listener , err := net.Listen("tcp","1234") 
if err != nil {
      log.Fatal("ListenTCP error:",err)
}
// 通过rpc.ServeConnl函数在该TCP链接上为对方提供RPC服务. /没Accept-一个请求,就创建一个goroutie进行处理 
for {
      conn,err listener.Accept() 
      if err != nil {
      log.Fatal("Accept error:",err)
}
//前面都是tcp的知识,到这个RPC就接管了
//因此你可以认为rPc帮我们封装消息到函数调用的这个逻辑,
//提升子王作效率,逻棉比校筒洁,可以看看他代码
gorpc.ServeConn(conn)

RPC Client

func main() {
		// 首先是通过rpc.Dial拨号RPC服务,建立连接
		client, err := rpc.Dial("tcp" , "localhost:1234")
		if err != nil {
				log.Fatal("dialing:", err)
 	   }
	//然后通过client.Call 调用具体的RPC方法
	//在调用client.Call时:
	//    第一个参数是用点号链接点PRC服务名字和方法名字。
	//    第二个参数是 请求参数
	//    第三个是请求响应,必须是一个指针,有底层的rpc服务帮你赋值
	var reply string
	err = client.Call("HellService.Hello" , "hello" , &reply)
	if err != nil {
		log.Fatal(err)
	}
  
	 fmt.Println(reply)
 }

## RPC的优点

- 可以像使用本地函数一样使用远程服务
    - 简单
    - 高效

## 谁能告诉我该怎么传参?
![请添加图片描述](https://img-blog.csdnimg.cn/9845e14837de4e699285037a520513c3.png)
**go原生的Call函数并不友好**

## 因此需要定义接口 ps:golang接口的用处大于其他语言,用于各个模块之间的结偶

````go
package service

const HelloServiceName = "HelloService"

type HelloService interface {

		Hello(request string, reply *string) error//相当于一个契约spec,无论客户端还是服务端都必须满足这个条件才能正常的调用
}

约束服务端和客户端

约束服务端
//通过接口约束HelloService服务
var _  service.HelloService = (*HelloService)(nil)

封装客户端,让其满足HelloService接口约束

var _ service.HelloService = (*HelloServiceClient)(nil)
//创建一个客户端对象
type HelloServiceClient struct {
		*rpc.Client
}

func DialHelloService(network, address string) (*HelloServiceClient, error) {
	c,err := rpc.Dial(network, address)
	if err != nil {
			return nil,err
	}
	return &HelloServiceClient{Client : c}, nil
}

func (p *HelloServiceClient) Hello(request string, reply *string) error{
	return p.Client.Call(service.HelloServiceName+".Hello",request,reply)
}

#### 基于接口约束后的客户端使用就要容易多了:
````go
func main() {
	client, err := DialHelloService("tcp", "localhost:1234")
	if err != nil {
		log.Fatal("dialing:", err)
	}

	var reply string
	err = client.Hello("hello", &reply)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(reply)
}

JSON ON TCP

  • PRC数据打包时可以通过插件实现自定义的编码和解码;
  • PRC建立在抽象的io.ReadWriteCloser接口之上,我们可以将RPC架设在不同的通讯协议之上。
服务端:
func main() {
	rpc.RegisterName("HelloService" , new(HelloService))
	listenner, err := net.Listen("tcp", ":1234")
	if err != nil {
		log.Fatal("ListenTCP error:", err)
	}
for {
	conn, err := listenner.Accept()
	if err != nil {
		log.Fatal("Accept error:", errr)
	}
	//代码中最大的变化是用rpc.ServeCodec函数替代了rpc.ServeConn函数
	//传入的参数是针对服务端的json编解码器
	go rpc.ServeCodec(jsonrpc.NewServerCodec(conn))
//go语言的rpc是建立在网络层之上的,在网络层之上有一个编码层,可以选择不通的编解码接口,比如gob、json、xml等
客户端
func DialHelloService(network, address string) (*HelloServiceClient, error) {
		//c,err := rpc.Dial(network, address)
		//if err != nil {
		//		return nil, err
		//}
		//建立链接
		conn, err := net.Dial("tcp", "localhost:1234")
		if err != nil {
			log.Fatal("net.Dial:", err)
		}

		//采用json编解码的客户端
		c := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(coon))
		return &HelloServiceClient{Client: c},nil
	}
	

REST规范的Handler+RPC Call

服务端:

func main() {
	rpc.RegisterName("HelloService", new(HelloService))

	//RPC的服务架设在"/jsonrpc"路径,
	//在处理函数中基于http.ResponseWriter和http.Request类型的参数构造一个io.ReadWriteCloser类型的conn通道。
	//然后基于conn构建针对服务端的json编码解码器
	//最后通过rpc.ServeRequest函数为每次请求处理一次RPC方法调用
	http.HandleFunc("/jsonrpc", func(w http.ResponseWriter, r * http.Request)) {
		conn := NewRPCReadWriteCloserFromHTTP(w,r)
		rpc.ServeRequest(jsonrpc.NewServerCodec(conn))
	})
	http.ListenAndServe(":1234",nil)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值