首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >golang源码分析:jsonrpc(2)

golang源码分析:jsonrpc(2)

作者头像
golangLeetcode
发布2026-03-18 18:18:26
发布2026-03-18 18:18:26
850
举报

在分析完client的实现后,我们继续看看server端的实现,首先我们定义下结构体

代码语言:javascript
复制
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代码

代码语言:javascript
复制
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

代码语言:javascript
复制
func NewServer() *Server {
    return &Server{}
}
代码语言:javascript
复制
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格式一样,这里就不重复介绍了

代码语言:javascript
复制
func (server *Server) Register(rcvr any) error {
    return server.register(rcvr, "", false)
}

然后是ServeCodec前面也介绍过了

代码语言:javascript
复制
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

代码语言:javascript
复制
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的格式定义了请求和返回值

代码语言:javascript
复制
type serverRequest struct {
    Method string           `json:"method"`
    Params *json.RawMessage `json:"params"`
    Id     *json.RawMessage `json:"id"`
}
代码语言:javascript
复制
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包来实现。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-06-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 golang算法架构leetcode技术php 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档