
在分析完client的实现后,我们继续看看server端的实现,首先我们定义下结构体
package model
type Item struct {
Id int `json:"id"`
Name string `json:"name"`
}
type Response struct {
Ok bool `json:"ok"`
Id int `json:"id"`
Message string `json:"msg"`
}然后是server代码
package main
import (
"log"
"net"
"net/rpc"
"net/rpc/jsonrpc"
"learn/vscode/jsonrpc/exp1/model"
)
// 服务端的rpc处理器
type ServiceHandler struct{}
func (serviceHandler *ServiceHandler) GetName(id int, item *model.Item) error {
log.Printf("receive GetName call, id: %d", id)
item.Id = id
item.Name = "学院君"
return nil
}
func (serviceHandler *ServiceHandler) SaveName(item model.Item, resp *model.Response) error {
log.Printf("receive SaveName call, Item: %v", item)
resp.Ok = true
resp.Id = item.Id
resp.Message = "存储成功"
return nil
}
func main() {
// 初始化 RPC 服务端
server := rpc.NewServer()
// 监听端口 8080
listener, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalf("监听端口失败:%v", err)
}
defer listener.Close()
log.Println("Start listen on port localhost:8080")
// 初始化服务处理器
serviceHandler := &ServiceHandler{}
// 注册处理器
err = server.Register(serviceHandler)
if err != nil {
log.Fatalf("注册服务处理器失败:%v", err)
}
// 等待并处理客户端连接
for {
conn, err := listener.Accept()
if err != nil {
log.Fatalf("接收客户端连接请求失败: %v", err)
}
// 自定义 RPC 编码器:新建一个 jsonrpc 编码器,并将该编码器绑定给 RPC 服务端处理器
go server.ServeCodec(jsonrpc.NewServerCodec(conn))
}
}定义一个json-rpc的server分三步:rpc.NewServer初始化一个服务、server.Register将service注册进去、定义一个编码器来处理每一个连接go server.ServeCodec(jsonrpc.NewServerCodec(conn)),接着我们依次分析下每一个部分。
初始化服务器很简单,源码位于net/rpc/server.go
func NewServer() *Server {
return &Server{}
}type Server struct {
serviceMap sync.Map // map[string]*service
reqLock sync.Mutex // protects freeReq
freeReq *Request
respLock sync.Mutex // protects freeResp
freeResp *Response
}register的过程和gob格式一样,这里就不重复介绍了
func (server *Server) Register(rcvr any) error {
return server.register(rcvr, "", false)
}然后是ServeCodec前面也介绍过了
func (server *Server) ServeCodec(codec ServerCodec) {
sending := new(sync.Mutex)
wg := new(sync.WaitGroup)
for {
service, mtype, req, argv, replyv, keepReading, err := server.readRequest(codec)
唯一不同的是参数里使用的是jsonrpc.NewServerCodec,可以看到,和Client一样,它的编码方式使用的是json
func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
return &serverCodec{
dec: json.NewDecoder(conn),
enc: json.NewEncoder(conn),
c: conn,
pending: make(map[uint64]*json.RawMessage),
}
}另外按照json rpc的格式定义了请求和返回值
type serverRequest struct {
Method string `json:"method"`
Params *json.RawMessage `json:"params"`
Id *json.RawMessage `json:"id"`
}type serverResponse struct {
Id *json.RawMessage `json:"id"`
Result any `json:"result"`
Error any `json:"error"`
}总结下,jsonrpc 和rpc包默认实现唯一的不同就是编码解码方式和参数格式,前者使用的是json和json-rpc协议,后者使用golang自带的gob编码方式,参数和返回值形式没有特殊要求。
所以在进行LLM开发的时候,如果有需要通过json-rpc协议来实现一些组件,比如实现mcp server,我们可以直接使用net/rpc/jsonrpc包来实现。
本文分享自 golang算法架构leetcode技术php 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!