
1、基本使用
1.1、概念梳理
TPC/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。
什么是RPC?
远程过程调用(Remote Procedure Call,缩写为 RPC)是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。如果涉及的软件采用面向对象编程,那么远程过程调用亦可称作远程调用或远程方法调用。
	
web3 和 http , RPC 之间的关系。
HttpProvider should be used to send rpc calls over http
web3有两种Provider, 一种是HttpProvider, 一种是IpcProvider
web3是通过http, ws, 发送Rpc调用,然后把Rpc调用的结果通过http,或者WS返回回来。
	
 
RPC主要是基于TCP/IP协议,而http服务则是基于HTTP协议
RPC(即Remote Procedure Call,远程过程调用)和HTTP(HyperText Transfer Protocol,超文本传输协议)他们最本质的区别,就是RPC主要工作在TCP协议之上,而HTTP服务主要是工作在HTTP协议之上,我们都知道HTTP协议是在传输层协议TCP之上的,所以效率来看的话,RPC当然是要更胜一筹。
HTTP与RPC存在重大不同的是:请求是使用具有标准语义的通用的接口定向到资源的,这些语义能够被中间组件和提供服务的来源机器进行解释。结果是使得一个应用支持分层的转换(layers of transformation)和间接层(indirection),并且独立于消息的来源,这对于一个Internet规模、多个组织、无法控制的可伸缩性的信息系统来说,是非常有用的。与之相比较,RPC的机制是根据语言的API(language API)来定义的,而不是根据基于网络的应用来定义的。
	
 
调用远程机器上的一个过程(procedure)的观念,是RPC与其他形式的基于网络的应用通信的区别所在。
RPC(Remote Procedure Call,远程过程调用)是建立在Socket之上的,出于一种类比的愿望,在一台机器上运行的主程序,可以调用另一台机器上准备好的子程序,就像 LPC(本地过程调用).RPC带来了开发C/S程序的简单可靠的手段,它通过一种叫XDR的数据表达方法描述数据,程序员书写伪代码,然后由 rpcgen程序翻译为真正的可编译的C语言源代码,再编译成真正的Client端和Server端程序。
RPC是在Socket的基础上实现的,它比socket需要更多的网络和系统资源.另外,在对程序优化时,程序员虽然可以直接修改由rpcgen产生的令人费解的源程序,但对于追求程序设计高效率的RPC而言,获得的简单性则被大大削弱.
1.2、go 语言 RPC实现方式
1. net/rpc库
rpc.server
	
package main
import (
   "net/rpc"
   "net"
)
type HelloService struct {
}
func (this *HelloService) SayHello(req string, reply *string) error {
   *reply = "hello:" + req
   return nil
}
func main() {
   rpc.RegisterName("HelloService", new(HelloService))
   listerner, err := net.Listen("tcp", ":9900")
   if err != nil {
      panic(err)
   }
   for {
      conn, err := listerner.Accept()
      if err != nil {
         panic(err)
      }
      rpc.ServeConn(conn)
   }
}
	
rpc_client.go
	
package main
import "net/rpc"
func main() {
   client, err := rpc.Dial("tcp", "localhost:9900")
   if err != nil {
      panic(err)
   }
   reply := ""
   err = client.Call("HelloService.SayHello", "alice", &reply)
   if err != nil {
      panic(err)
   }
   println(reply)
}
	
2.net/rpc/jsonrpc库
rpc_server.go
	
package main
import (
   "net"
   "net/rpc"
   "net/rpc/jsonrpc"
)
//注意字段必须是导出
type Params struct {
   Width, Height int
}
type Rect struct{}
func (r *Rect) Area(p Params, ret *int) error {
   *ret = p.Width * p.Height
   return nil
}
func main() {
   rect := new(Rect)
   //注册rpc服务
   rpc.Register(rect)
   //监听端口
   tcplisten, _ := net.Listen("tcp", ":8080")
   for {
      conn, err3 := tcplisten.Accept()
      if err3 != nil {
         continue
      }
      //这里使用jsonrpc进行处理
      go rpc.ServeCodec(jsonrpc.NewServerCodec(conn))
      //go jsonrpc.ServeConn(conn)
   }
}
	
rpc_client.go
	
package main
import (
   "fmt"
   "log"
   "net/rpc/jsonrpc"
)
//注意字段必须是导出
type Params1 struct {
   Width, Height int
}
func main() {
   //连接远程rpc服务
   //这里使用jsonrpc.Dial
   rpc, err := jsonrpc.Dial("tcp", "127.0.0.1:8080")
   if err != nil {
      log.Fatal(err)
   }
   ret := 0
   //调用远程方法
   //注意第三个参数是指针类型
   err2 := rpc.Call("Rect.Area", Params1{50, 100}, &ret)
   if err2 != nil {
      log.Fatal(err2)
   }
   fmt.Println(ret)
}
	
3.http上的RPC
rpc_server.go
	
package main
import (
   "net/rpc"
   "net"
   "log"
   "net/http"
)
//自己的数据类
type MyMath struct{
}
//加法--只能两个参数--方法名第一个字母必须大写
func (mm *MyMath) Add(num map[string]int,reply *int) error {
   *reply = num["num1"] + num["num2"]
   return nil
}
func main() {
   //注册MyMath类,以代客户端调用
   rpc.Register(new(MyMath))
   rpc.HandleHTTP()
   l, e := net.Listen("tcp", ":1215")
   if e != nil {
      log.Fatal("listen error:", e)
   }
   http.Serve(l, nil)
}
	
rpc_client.go
	
package main
import (
   "net/rpc"
   "fmt"
   "log"
)
func main() {
   //连接服务
   client, err := rpc.DialHTTP("tcp", "127.0.0.1:1215")
   if err != nil {
      log.Fatal("dialing:", err)
   }
   var reply int
   var num = make(map[string]int)
   num["num1"] = 3
   num["num2"] = 2
   //调用远程MyMath的Add方法,也只能是三个参数
   err = client.Call("MyMath.Add",num,&reply)
   if err != nil {
      log.Fatal("arith error:", err)
   }
   //输出结果
   fmt.Println(reply)
   client.Close()
}
	
4.protobuf版rpc
proto文件
	
syntax = "proto3";
package pb;
// 算术运算请求结构
message ArithRequest {
    int32 a = 1;
    int32 b = 2;
}
// 算术运算响应结构
message ArithResponse {
    int32 pro = 1;  // 乘积
    int32 quo = 2;  // 商
    int32 rem = 3;  // 余数
}
// rpc方法
service ArithService {
    rpc multiply (ArithRequest) returns (ArithResponse);    // 乘法运算方法
    rpc divide (ArithRequest) returns (ArithResponse);      // 除法运算方法
}
	
rpc_server.go
	
package main
import (
   "test/rpc/pb"
)
// 算术运算结构体
type Arith struct {
}
// 乘法运算方法
func (this *Arith) Multiply(req *pb.ArithRequest, res *pb.ArithResponse) error {
   res.Pro = req.GetA() * req.GetB()
   return nil
}
func main() {
   pb.ListenAndServeArithService("tcp", "127.0.0.1:8097", new(Arith))
}
	
rpc_client.go
	
package main
import (
   "fmt"
   "log"
   "test/rpc/pb"
)
func main() {
   conn, err := pb.DialArithService("tcp", "127.0.0.1:8097")
   if err != nil {
      log.Fatalln("dailing error: ", err)
   }
   defer conn.Close()
   req := &pb.ArithRequest{9, 2}
   res, err := conn.Multiply(req)
   if err != nil {
      log.Fatalln("arith error: ", err)
   }
   fmt.Printf("%d * %d = %d\n", req.GetA(), req.GetB(), res.GetPro())
}
	
扫码二维码 获取免费视频学习资料

- 本文固定链接: http://phpxs.com/post/7265/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料
 
			








