本文共 2834 字,大约阅读时间需要 9 分钟。
因为内置net/rpc包接口设计的缺陷,通过追踪 rpc.HandleHTTP()
方法,找到 ServeHTTP
方法:
func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { if req.Method != "CONNECT" { w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.WriteHeader(http.StatusMethodNotAllowed) io.WriteString(w, "405 must CONNECT\n") return } conn, _, err := w.(http.Hijacker).Hijack() if err != nil { log.Print("rpc hijacking ", req.RemoteAddr, ": ", err.Error()) return } io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n") server.ServeConn(conn)}func (server *Server) ServeConn(conn io.ReadWriteCloser) { buf := bufio.NewWriter(conn) srv := &gobServerCodec{ rwc: conn, dec: gob.NewDecoder(conn), enc: gob.NewEncoder(buf), encBuf: buf, } server.ServeCodec(srv)}
根本就没有设置codec的参数,直接写死了 gob ,所以依赖于 net/rpc 包的除了 gob 之外的编码方式都只能使用 tcp 协议。
我们无法使用jsonrpc等定制的编码作为rpc.DialHTTP的底层协议,如果需要让jsonrpc支持rpc.DialHTTP函数,需要调整rpc的接口。
除了传输协议,还有可以指定一个RPC编码协议,用于编码/解码RPC调用的函数参数和返回值,RPC调用不指定编码协议时,默认采用Go语言特有的gob编码协议。
因为,, 其他语言一般都不支持Go语言的gob协议,因此如果需要跨语言RPC调用就需要采用通用的编码协议。
Go的标准库还提供了一个"net/rpc/jsonrpc"
包,用于提供基于JSON编码的RPC支持。
JSON RPC采用JSON进行数据编解码,因而支持跨语言调用。但目前的jsonrpc库是基于tcp协议实现的,暂时不支持使用http进行数据传输。
定义服务
package repoimport ( "errors")type Order struct { }type OrderInfo struct { Id string Price float64 Status int}func (o *Order) GetOne(orderId string, orderInfo *OrderInfo) error { if orderId == "" { return errors.New("orderId is invalid") } *orderInfo = OrderInfo{ Id: orderId, Price: 100.00, Status: 1, } return nil}
服务端
package mainimport ( "log" "net" "net/rpc" "net/rpc/jsonrpc" "demo1/go-rpc/repo")func main() { err := rpc.Register(new(repo.Order)) if err != nil { log.Fatal(err) } l, err := net.Listen("tcp", ":8100") if err != nil { log.Fatal(err) } for { conn, e := l.Accept() if e != nil { continue } go jsonrpc.ServeConn(conn) }}
客户端
package mainimport ( "fmt" "log" "net/rpc/jsonrpc" "demo1/go-rpc/repo")func main() { client, err := jsonrpc.Dial("tcp", "127.0.0.1:8100") if err != nil { log.Fatal("dialing:", err) } orderId := "asddddddd" var orderInfo repo.OrderInfo err = client.Call("Order.GetOne", orderId, &orderInfo) if err != nil { log.Fatal("Order error:", err) } fmt.Println(orderInfo)}
jsonrpc 中的协议说明
使用tcp工具连接测试
1、请求参数列表
id int 编号,默认是0method string 要调用的方法params 参数,数组或者是map,如果参数是单个的值应转换成数组。
例如
{ "method":"Order.GetOne","params":["asddddddd"],"id":0}{ "method":"Order.GetOne","params":{ "A":9,"B":2},"id":0}
2、响应参数
id int 编号,默认是0result 结果error string 错误信息
如果成功,返回结果:
{ "id":0,"result":{ "Id":"asddddddd","Price":100,"Status":1},"error":null}
如果失败,返回结果:
{ "id":0,"result":null,"error":"rpc: can't find service Arith.Multiply"}{ "id":0,"result":null,"error":"json: cannot unmarshal string into Go value of type [1]interface {}"}
转载地址:http://ojaui.baihongyu.com/