2017-07-03 2 views
0

J'essaie d'apprendre comment fonctionne JSON-RPC et de le tester en langage Go (golang). Le programme Go fonctionne très bien. Il fait ce qu'il devrait faire. Mais quand j'essaye de faire une requête brute via telnet, cela donne une erreur.JSON-RPC, "impossible de déformer l'objet"

Le travail et super simple serveur JSON-RPC est décrit ici:

// 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 
     } 
    } 

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

Le travail et super simple code de client JSON-RPC suit:

// 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 
    } 

Encore une fois. Ce programme golang fonctionne bien.

Mais la prochaine chose que je ne peux pas comprendre.

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 {}"} 

S'il vous plaît, donnez-moi quelques conseils ou la raison d'une telle erreur. Quel est le problème dans la demande brute?

Merci d'avance!

+0

mise en œuvre actuelle du net/rpc/jsonrpc prendre 1 argument pour l'argument struct. https://github.com/golang/go/blob/5fea2ccc77eb50a9704fa04b7c61755fe34e1d95/src/net/rpc/jsonrpc/server.go#L91-L97 Si vous souhaitez passer des arguments nommés, passez en tant que tranche de struct. – mattn

Répondre

1

Votre code semble correct.

Mais dans la demande, params devrait être un tableau contenant les paramètres réels.

Essayez avec la charge utile suivante et il devrait fonctionner:

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

(Notez le "[" et "]" enfermant le param réelle)

+0

Ça marche! Un grand merci à vous :) – Chelovek