Go net/rpc gob编码报错elliptic.p256Curve类型未注册求助
问题背景
Go语言RPC通信过程中,服务端无法返回正确的计算结果,运行时报错信息如下:
2022/06/20 19:58:35 rpc: gob error encoding body: gob: type not registered for interface: elliptic.p256Curve
相关业务代码:
package main import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" f "fmt" "log" "net" "net/rpc" ) type Calc int //RPC服务注册用的自定义类型 type Args struct { A, B int } type Reply struct { //返回值结构 PrivateKey ecdsa.PrivateKey PublicKey []byte } func (c *Calc) Get(args Args, reply *Reply) error { private, public := NewKeyPair() reply.PrivateKey = private reply.PublicKey = public return nil } func main() { rpc.Register(new(Calc)) ln, err := net.Listen("tcp", ":6000") if err != nil { f.Println(err) return } defer ln.Close() for { conn, err := ln.Accept() if err != nil { continue } f.Println("Connected") defer conn.Close() go rpc.ServeConn(conn) } } func NewKeyPair() (ecdsa.PrivateKey, []byte) { curve := elliptic.P256() private, err := ecdsa.GenerateKey(curve, rand.Reader) if err != nil { log.Panic(err) } pubKey := append(private.PublicKey.X.Bytes(), private.PublicKey.Y.Bytes()...) return *private, pubKey }
故障原因
Go标准库net/rpc默认使用gob作为序列化协议,gob在序列化接口类型值时,要求必须提前注册接口对应的具体实现类型,否则无法完成编码。
代码中Reply结构体直接返回ecdsa.PrivateKey类型,该结构体内部的Curve字段是elliptic.Curve接口类型,实际赋值的是标准库未导出的elliptic.p256Curve实现,没有提前注册到gob的类型列表中,所以序列化时抛出类型未注册的错误。
修复方案
有两种可行修复方式,按需选择即可:
- 方案1:提前注册曲线类型到gob
在服务端和客户端的初始化逻辑(比如main函数开头、init函数)中,添加gob类型注册代码,把用到的椭圆曲线实例注册进去:
该方案改动最小,不需要修改原有结构体定义,但要注意服务端和客户端必须注册完全一致的类型集合,否则会出现反序列化失败问题。import "encoding/gob" func init() { // 用到什么曲线就注册什么,这里用了P256就注册P256,用P384/P521同理添加对应注册 gob.Register(elliptic.P256()) } - 方案2:不要直接传输密钥结构体,转成字节切片传输
这是更通用的跨服务传输密钥的做法,避免序列化结构体带来的兼容问题:在服务端生成密钥后,把私钥序列化成DER/PEM格式的字节流放到Reply中返回,客户端收到字节流后再反序列化成ecdsa.PrivateKey实例即可,不需要额外注册gob类型。
内容的提问来源于stack exchange,提问作者kojaejin
相关产品推荐
相关产品推荐

