提到微服务,老生常谈的就是服务间的通信,主要有两种方式
同步调用:rpc 远程过程调用
rpc协议:主要包括
1、传输协议(http1.1、http2.0、wensocket协议、http3.0)
2、传输格式(JSON、Protobuf、xml)
异步调用:消息队列 kafka,activeMQ,rocketMQ
net/rpc包
先来了解socket通信
server端 伪代码
listener :=net.listen() //获取监听器对象
conn :=listener.Accept() //等待连接
conn.read() //读到客户端发送的数据
conn.write() //向客户端发送数据
conn.close() //关闭连接
listener.close //关闭监听器
client端 伪代码
conn :=net.Dial() //连接服务端
conn.write() //发送数据
conn.read() // 接收返回数据
conn.close() // 关闭连接
RPC使用
server端
//注册rpc服务对象
rpc.RegisterName("服务名",回调函数)
//创建监听器
listener,err := net.Listen()
//建立连接
conn ,err := listener.Accept()
//绑定rpc服务到连接上
rpc.ServeConn(conn)
client端
//连接rpc服务端
conn,err ;=rpc.Dial()
//调用服务
conn.Call("服务名.方法名",传入参数,传出参数)
贴一下代码
server端
package main
import (
"log"
"net"
"net/rpc"
"strconv"
"time"
)
// 定义服务
type Order struct{}
func (this *Order) GetOrder(req string, resp *string) error {
*resp = req + strconv.Itoa(int(time.Now().UnixNano()))
return nil
}
func main() {
//注册rpc服务
rpc.RegisterName("order", new(Order))
//设置监听
listener, err := net.Listen("tcp", "127.0.0.1:80")
if err != nil {
log.Fatal("监听错误")
}
defer listener.Close()
//获取链接
accept, err := listener.Accept()
if err != nil {
log.Fatal("获取连接错误")
}
defer accept.Close()
//绑定服务与链接
rpc.ServeConn(accept)
}
client端
package main
import (
"fmt"
"log"
"net/rpc"
)
func main() {
//连接客户端
client, err := rpc.Dial("tcp", "127.0.0.1:80")
if err != nil {
log.Fatal("连接服务的错误")
}
defer client.Close()
//调用服务
var resp string
err = client.Call("order.GetOrder", "lijialin", &resp)
fmt.Println(err)
fmt.Println(resp)
}
了解了原始RPC,我们可以对原始RPC进行封装,为后面学习GRPC做铺垫
先来说一下为什么要封装:如下图所示,Order结构体绑定的方法是有一定限制条件的,如果写错了,那么在编译时是不会报错的,但是在运行时会报错,本着报错宜早不宜迟的原则,我们可以是由接口对服务实现类进行限制。
第一步:新建文件packaging.go用于定义接口(该文件如果你是要框架可以让框架生成,但是了解他会加深你对GRPC框架的印象)
定义好接口我们在编写服务时如果格式不对,会在编译时发现没有如下图所示的标记
额外的,我们可以对注册服务进行封装,防止字符串写错
在packaging文件中声明注册函数
修改注册服务的代码
再来看客户端,如下图所示我们可以对rpc.Dial方法进行封装
还可以对client.Call这段代码进行封装(因为目前这些字符串是写死的,服务名和方法名如果写错不死很尬)
因此我们定义结构体MyClient嵌套rpc.Client的指针对象,并绑定Call方法
更改main.go文件的代码
对于rpc.Dial()方法的封装我自己觉得没什么必要
OK今天的学习到此结束,累他妈死老子了