go语言rpc初体验

go语言rpc初体验

go 复制代码
package main

import (
	"net"
	"net/rpc"
)

// 注册一个接口进来
type HelloService struct {
}

func (s *HelloService) Hello(request string, replay *string) error {
	//返回值是通过修改replay的值
	*replay = "hello " + request
	return nil
}

// go语言内置rpc包
func main() {
	//注册名字 实例化一个sever
	listener, _ := net.Listen("tcp", ":1234") //监听
	//注册处理handle
	_ = rpc.RegisterName("HelloService", &HelloService{})
	//启动服务
	conn, _ := listener.Accept() //当一个新的连接进来的时候,生成套接字
	rpc.ServeConn(conn)          //调用一次连接就结束
}
go 复制代码
package main

import (
	"fmt"
	"net/rpc"
)

func main() {
	//建立连接
	client, err := rpc.Dial("tcp", "localhost:1234")

	if err != nil {
		panic("连接失败")
	}

	//var replay *string //reading body gob:DecodeValue of unassignable value 传递的nil 没有地址

	//var replay *string = new(string) //new 是分配一个空间 第一种方法
	var replay string //string有默认值 第二种方法
	err = client.Call("HelloService.Hello", "bobby", &replay)

	if err != nil {
		panic("调用失败")
	}

	fmt.Println(replay)
}

一连串的代码大部分都是net的包好像和rpc没有关系?

答:不行,rpc调用中有几个问题需要解决:1:call id,2序列化和反序列化

可以跨语言调用呢? 1. go语言的rpc的序列化协议是什么(Gob) 2. 能否替换成常见的序列化

替换rpc的传输协议为json

go 复制代码
package main

import (
	"net"
	"net/rpc"
	"net/rpc/jsonrpc"
)

// 注册一个接口进来
type HelloService struct {
}

func (s *HelloService) Hello(request string, replay *string) error {
	//返回值是通过修改replay的值
	*replay = "hello " + request
	return nil
}

// go语言内置rpc包
func main() {
	//注册名字 实例化一个sever
	listener, _ := net.Listen("tcp", ":1234") //监听
	//注册处理handle
	_ = rpc.RegisterName("HelloService", &HelloService{})
	for { //如果使用死循环,有一个弊端如果同时多个客户端处理,需要一个一个处理,所以需要加协程
		//启动服务
		conn, _ := listener.Accept() //当一个新的连接进来的时候,生成套接字
		//但使用指定的编解码器,以编码请求主体和解码回复主体。
		go rpc.ServeCodec(jsonrpc.NewServerCodec(conn)) //后面传来的东西,然后支持的编码都可以
	}

}

如果使用死循环,有一个弊端如果同时多个客户端处理,需要一个一个处理,所以需要加协程

go 复制代码
package main

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

func main() {
	//建立连接
	conn, err := net.Dial("tcp", "localhost:1234")

	if err != nil {
		panic("连接失败")
	}

	//jsonrpc.NewClientCodec(conn) 包装连接变成一个新的conn
	client := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(conn)) //因为他是json的格式
	var replay string                                              //string有默认值 第二种方法
	err = client.Call("HelloService.Hello", "bobby", &replay)      //发送数据格式为json

	if err != nil {
		panic("调用失败")
	}

	fmt.Println(replay)
}

修改rpc调用代码

client.go

go 复制代码
package main

import (
	"awesomeProject123/new_helloworld/client_proxy"
	"fmt"
)

func main() {
	//建立连接

	//1 只想写业务逻辑,不想关注每个函数的名称
	//客户端部分
	client := client_proxy.NewHelloServiceClient("tcp", "localhost:1234")

	//jsonrpc.NewClientCodec(conn) 包装连接变成一个新的conn
	var replay string                     //string有默认值 第二种方法
	err := client.Hello("bobby", &replay) //发送数据格式为json

	if err != nil {
		panic("调用失败")
	}

	fmt.Println(replay)
}

client_proxy.go

go 复制代码
package client_proxy

import (
	"awesomeProject123/new_helloworld/handler"
	"net/rpc"
)

type HelloServerStub struct {
	*rpc.Client
}

// NewHelloServiceClient 在go语言中没有类、对象,就意味着没有初始化方法
func NewHelloServiceClient(protol, address string) HelloServerStub {
	conn, err := rpc.Dial(protol, address)
	if err != nil {
		panic("connect error!")
	}

	return HelloServerStub{conn}
}

func (c *HelloServerStub) Hello(request string, replay *string) error {

	err := c.Call(handler.HelloServiceName+".Hello", request, replay)
	if err != nil {
		return err
	}
	return nil
}

server.go

go 复制代码
package main

import (
	"awesomeProject123/new_helloworld/handler"
	"awesomeProject123/new_helloworld/server_proxy"
	"net"
	"net/rpc"
)

// go语言内置rpc包
func main() {
	//注册名字 实例化一个sever
	listener, _ := net.Listen("tcp", ":1234") //监听
	//注册处理handler
	_ = server_proxy.RegisterHelloService(&handler.NewHelloService{})
	//_ = rpc.RegisterName(handler.HelloServiceName, &handler.HelloService{})
	for {
		//启动服务
		conn, _ := listener.Accept() //当一个新的连接进来的时候,生成套接字
		rpc.ServeConn(conn)          //调用一次连接就结束
	}
}

server_proxy.go

go 复制代码
package server_proxy

import (
	"awesomeProject123/new_helloworld/handler"
	"net/rpc"
)

type HelloServicer interface {
	Hello(request string, replay *string) error
}

// RegisterHelloService 解耦  --我们关心的是函数,鸭子类型
func RegisterHelloService(srv HelloServicer) error {

	return rpc.RegisterName(handler.HelloServiceName, srv)
}

protoc安装

https://github.com/protocolbuffers/protobuf/releases

相关推荐
飞剑神2 小时前
qt svg缺失元素, 原因是不支持 rgba
开发语言·qt
眠りたいです3 小时前
Qt音频播放器项目实践:文件过滤、元数据提取与动态歌词显示实现
c++·qt·ui·音视频·媒体·qt5·mime
七七&55612 小时前
2024年08月13日 Go生态洞察:Go 1.23 发布与全面深度解读
开发语言·网络·golang
java坤坤12 小时前
GoLand 项目从 0 到 1:第八天 ——GORM 命名策略陷阱与 Go 项目启动慢问题攻坚
开发语言·后端·golang
元清加油12 小时前
【Golang】:函数和包
服务器·开发语言·网络·后端·网络协议·golang
恋喵大鲤鱼15 小时前
Golang 后台技术面试套题 1
面试·golang
奇树谦16 小时前
QT|windwos桌面端应用程序开发,当连接多个显示器的时候,如何获取屏幕编号?
开发语言·qt
Franklin19 小时前
Python界面设计【QT-creator基础编程 - 01】如何让不同分辨率图像自动匹配graphicsView的窗口大小
开发语言·python·qt
郝学胜-神的一滴19 小时前
深入理解QFlags:Qt中的位标志管理工具
开发语言·c++·qt·程序人生
看到我,请让我去学习1 天前
Qt— 布局综合项目(Splitter,Stacked,Dock)
开发语言·qt