2017-07-03 60 views
0

我想了解JSON-RPC如何工作,并使用Go语言(golang)进行测试。 Go程序正常工作。它做它应该做的事情。但是当我尝试通过telnet发出一个原始请求时,它会给出一个错误。JSON-RPC,“无法解组对象”

工作和超级简单的JSON-RPC服务器描述如下:

// rpc_json_server.go 

    package main 

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

    //------------------------------------------------------------------------------ 
    // Types 
    //------------------------------------------------------------------------------ 

    type Arithmetic int // Used as RPC Service called 'Arithmetic' 

    type Arguments struct { 
     A int 
     B int 
    } 

    type Result int 

    //------------------------------------------------------------------------------ 
    // Methods 
    //------------------------------------------------------------------------------ 

    func (t *Arithmetic) Multiply(args *Arguments, res *Result) error { 

     *res = Result(args.A * args.B) 

     return nil 
    } 

    //------------------------------------------------------------------------------ 

    func main() { 

     var srv *rpc.Server 
     var err error 
     var arith *Arithmetic 
     var listener net.Listener 
     var codec rpc.ServerCodec 
     var srv_conntype, srv_host, srv_port, srv_addr, srv_path string 
     var srv_debugPath string 
     var connection net.Conn 

     srv_conntype = "tcp" 
     srv_host = "0.0.0.0" 
     srv_port = "3000" 
     srv_addr = srv_host + ":" + srv_port 
     srv_path = "/" 
     srv_debugPath = "/debug" 

     // Create Server, register Service 
     srv = rpc.NewServer() 
     arith = new(Arithmetic) 
     err = srv.Register(arith) 
     if err != nil { 
      log.Fatalf("Error. Service Format is not correct. %s\r\n", err) //dbg 
     } 

     // Handle, listen 
     srv.HandleHTTP(srv_path, srv_debugPath) 
     listener, err = net.Listen(srv_conntype, srv_addr) 
     if err != nil { 
      log.Fatalf("Error. Can not listen on %s. %s\r\n", srv_addr, err) //dbg 
     } 
     log.Printf("Started RPC Handler at %s.\r\n", srv_addr) //dbg 

     // Serve 
     for { 

      connection, err = listener.Accept() 
      if err != nil { 
       log.Fatal(err) 
      } 

      codec = jsonrpc.NewServerCodec(connection) 

      go srv.ServeCodec(codec) 
     } 

     err = http.Serve(listener, nil) 
     if err != nil { 
      log.Fatalf("Serve Error. %s\r\n", err) //dbg 
     } 
    } 

    //------------------------------------------------------------------------------ 

工作和超级简单的JSON-RPC客户端的代码如下:

// rpc_json_client.go 

    package main 

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

    //------------------------------------------------------------------------------ 
    // Types 
    //------------------------------------------------------------------------------ 

    type Arithmetic int // Used as RPC Service called 'Arithmetic' 

    type Arguments struct { 
     A int 
     B int 
    } 

    type Result int 

    //------------------------------------------------------------------------------ 
    // Methods 
    //------------------------------------------------------------------------------ 

    func main() { 

     var err error 
     var srv_conntype, srv_host, srv_port, srv_addr string 
     //var srv_path string 
     var client *rpc.Client 
     var args Arguments 
     var result Result 
     var serviceName, methodName, funcName string 
     var connection net.Conn 

     srv_conntype = "tcp" 
     srv_host = "0.0.0.0" 
     srv_port = "3000" 
     srv_addr = srv_host + ":" + srv_port 
     //srv_path = "/" 

     // Connect to RPC Server 
     connection, err = net.Dial(srv_conntype, srv_addr) 
     if err != nil { 
      log.Fatalf("Error. Can not connect to %s. %s\r\n", srv_addr, err) //dbg 
     } 
     defer connection.Close() 

     // Client 
     client = jsonrpc.NewClient(connection) 

     // Prepare Call 
     serviceName = "Arithmetic" 
     methodName = "Multiply" 
     funcName = serviceName + "." + methodName 
     args.A = 7 
     args.B = 8 

     // Call remote Procedure 
     err = client.Call(funcName, args, &result) 
     if err != nil { 
      log.Fatalf("Error. %s\r\n", err) //dbg 
     } 

     // Show Results 
     fmt.Printf("[%d; %d] -> [%d].\r\n", args.A, args.B, result) //dbg 
    } 

一次。这个golang程序工作正常。

但接下来的事情我不明白。

telnet localhost 3000 
    Trying 127.0.0.1... 
    Connected to localhost. 
    Escape character is '^]'. 
    { 
    "jsonrpc":"2.0", 
    "method":"Arithmetic.Multiply", 
    "params": { "A": 5, "B": 6 }, 
    "id":1 
    } 
    {"id":1,"result":null,"error":"json: cannot unmarshal object into Go value of type [1]interface {}"} 

请给我一些建议或这种错误的原因。原始请求中有什么错误?

在此先感谢!

+0

当前实现净利润/ RPC的/ jsonrpc取1种说法为结构参数。 https://github.com/golang/go/blob/5fea2ccc77eb50a9704fa04b7c61755fe34e1d95/src/net/rpc/jsonrpc/server.go#L91-L97如果你想传递命名参数,请以结构片的形式传递。 – mattn

回答

1

你的代码似乎很好。

但是在请求中,params预计是包含实际参数的数组。

试着用以下的有效载荷,它应该工作:

{ 
    "jsonrpc":"2.0", 
    "method":"Arithmetic.Multiply", 
    "params": [ { "A": 5, "B": 6 } ], 
    "id":1 
} 

(请注意 “[” 和 “]” 包围实际PARAM)

+0

它的工作原理!非常感谢你:) – Chelovek