FAQ
Hello,

I have a working RPC TCP service written in Go, but when using Ruby to
connect to the service it hangs because no data appears to be sent back
through the open socket connection.

Remote RPC Function:

     package remote

     import "fmt"

     // Compose is our RPC functions return type
     type Compose string

     // Details is our exposed RPC function
     func (c *Compose) Details(arg string, reply *string) error {
         fmt.Printf("Arg received: %+v\n", arg)
         *c = "some value"
         *reply = "Blah!"
         return nil
     }


Remote RPC Endpoint Exposed:

     package remote

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

     // Endpoint exposes our RPC over TCP service
     func Endpoint() {
         compose := new(Compose)
         rpc.Register(compose)

         listener, err := net.Listen("tcp", ":8080")
         // error handling omitted

         for {
             conn, err := listener.Accept()
             // error handling omitted

             go rpc.ServeConn(conn)
         }
     }


Client Connection over TCP to Remote RPC function (using Golang so I know
it works at least in that respect):

     package main

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

     func main() {
         client, err := rpc.Dial("tcp", "localhost:8080")
         if err != nil {
             log.Fatal("dialing:", err)
         }

         var reply string

         e := client.Call("Compose.Details", "my string", &reply)
         if e != nil {
             log.Fatalf("Something went wrong: %v", e.Error())
         }

         fmt.Printf("The 'reply' pointer value has been changed to: %s",
reply)
     }


Here is the Ruby code I'm attempting to use:

     require "socket"
     require "json"


     socket = TCPSocket.new "localhost", "8080"


     b = {
       method: "Compose.Details",
       params: "foobar"
     }


     socket.write(JSON.dump(b))


     resp = JSON.load(socket.readline)


     p resp


The reason I think it doesn't work is because the Go RPC requires a pointer
to be provided as the second argument to the exposed RPC function but I'm
not sure how that works in a different programming language such as Ruby?

I've also tried utilising a library such as
https://github.com/chriskite/jimson

     require "jimson"


     client = Jimson::Client.new("localhost:8080")
     result = client.Details("foobar")


But all I get back is:

     RestClient::ServerBrokeConnection: Server broke connection

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

  • Jesse McNelis at Feb 16, 2016 at 3:18 am

    On 15 Feb 2016 11:39 p.m., wrote:
    Hello,

    I have a working RPC TCP service written in Go, but when using Ruby to
    connect to the service it hangs because no data appears to be sent back
    through the open socket connection.

    You need to use the net/rpc/jsonrpc pkg
    https://golang.org/pkg/net/rpc/jsonrpc/

    The rpc pkg uses gob encoding by default and your Ruby client is trying to
    send it json.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Mark Mcdx at Feb 17, 2016 at 6:55 am
    Hi Jessie,

    I only used json in that Ruby example as that was the only example i could find online as how to get Ruby to talk to a Go RPC over TCP.

    Do you know how another language (like Ruby) is supposed to pass the function identifier down the socket?

    I assume with a socket I need to write the data in a particular format for the receiving end of the socket to know how to deal with it?

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Ingo Oeser at Feb 17, 2016 at 8:52 am
    Your Go client and server *both* speak Gob instead of JSON with each other,
    so they understand each other.
    But your Ruby client talks JSON.

    Steps to fix:
      * in your server replace rpc.ServeConn(conn) with jsonrpc.ServeConn(conn)
    and fixup imports
      * in your go client replace rpc.Dial("tcp", "localhost:8080") with
    jsonrpc.Dial("tcp", "localhost:8080") and fixup imports

    Note: Fixup imports means to ensure you import "net/rpc/jsonrpc" instead of
    "net/rpc" in your Go client and server.

    Then your Ruby-Client should start working.

    On Wednesday, February 17, 2016 at 7:55:26 AM UTC+1, mark...@gmail.com
    wrote:
    Hi Jessie,

    I only used json in that Ruby example as that was the only example i could
    find online as how to get Ruby to talk to a Go RPC over TCP.

    Do you know how another language (like Ruby) is supposed to pass the
    function identifier down the socket?

    I assume with a socket I need to write the data in a particular format for
    the receiving end of the socket to know how to deal with it?
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Mark Mcdx at Feb 17, 2016 at 9:28 am
    Aha! ok so that was the missing piece for me :-)

    I didn't realise that net/rpc only worked with Go clients as they speak https://golang.org/pkg/encoding/gob/ with the server (i need to read that link to understand what Gob is still).

    I've switched to jsonrpc but using the example above, I'm now getting back `{"id"=>nil, "result"=>nil, "error"=>"json: cannot unmarshal string into Go value of type [1]interface {}"}` which I'm not sure how to resolve.

    Any tips or further enlightenment you can give me would be greatly appreciated.

    Hopefully the example is simple enough that it'll be clear to someone (who knows what they're doing) as to what the problem is

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Mark Mcdx at Feb 18, 2016 at 8:56 am
    Right, so I have this closer to working, but not quite...

    Here's the updated Ruby client:

    require "socket"
    require "json"

    socket = TCPSocket.new "localhost", "8080"

    b = {
       method: "Compose.Details",
       params: [{ :args => { :foo => "Foo!", :bar => "Bar!" }, :id => "0" }]
    }

    socket.write(JSON.dump(b))

    p JSON.load(socket.readline)

    Followed by the updated Go client:

    package remote

    import "fmt"

    // Args is structured around the client's provided parameters
    type Args struct {
      foo string
      bar string
    }

    // Compose is our RPC functions return type
    type Compose string

    // Details is our exposed RPC function
    func (c *Compose) Details(args *Args, reply *string) error {
      fmt.Printf("Args received: %+v\n", args)
      *c = "some value"
      *reply = "Blah!"
      return nil
    }

    When I run this my Ruby client sees the following:

    {"id"=>nil, "result"=>"Blah!", "error"=>nil}

    So I'm getting a result back, but if my actual RPC code tried to use the
    provided args in any way to generate the result then this would be a broken
    example because the stdout I get from the Go RPC function is a set of empty
    arg values?

    Args received: &{foo: bar:}


    I'm not sure why the RPC function isn't able to pull in the arguments I've
    provided to it?


    Also the "id" key: why would I get one back from the RPC function? and how
    can I give it a meaningful value?


    I tried setting an "id" key with a value from my Ruby client but that
    didn't effect the response from the Go RPC.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Mark Mcdx at Feb 18, 2016 at 10:01 am
    Here's the solution...

    # Details of JSON structure can be found here:
    # https://golang.org/src/net/rpc/jsonrpc/client.go#L45
    # Thanks to Albert Hafvenström (@albhaf) for his help
    b = {
       :method => "Compose.Details",
       :params => [{ :Foo => "Foo!", :Bar => "Bar!" }],
       :id => "0" # id is just echo'ed back to the client
    }

    And making sure the fields in Go are public:

    type Args struct {
      Foo string
      Bar string
    }

    On Monday, 15 February 2016 12:39:29 UTC, mark...@gmail.com wrote:

    Hello,

    I have a working RPC TCP service written in Go, but when using Ruby to
    connect to the service it hangs because no data appears to be sent back
    through the open socket connection.

    Remote RPC Function:

    package remote

    import "fmt"

    // Compose is our RPC functions return type
    type Compose string

    // Details is our exposed RPC function
    func (c *Compose) Details(arg string, reply *string) error {
    fmt.Printf("Arg received: %+v\n", arg)
    *c = "some value"
    *reply = "Blah!"
    return nil
    }


    Remote RPC Endpoint Exposed:

    package remote

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

    // Endpoint exposes our RPC over TCP service
    func Endpoint() {
    compose := new(Compose)
    rpc.Register(compose)

    listener, err := net.Listen("tcp", ":8080")
    // error handling omitted

    for {
    conn, err := listener.Accept()
    // error handling omitted

    go rpc.ServeConn(conn)
    }
    }


    Client Connection over TCP to Remote RPC function (using Golang so I know
    it works at least in that respect):

    package main

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

    func main() {
    client, err := rpc.Dial("tcp", "localhost:8080")
    if err != nil {
    log.Fatal("dialing:", err)
    }

    var reply string

    e := client.Call("Compose.Details", "my string", &reply)
    if e != nil {
    log.Fatalf("Something went wrong: %v", e.Error())
    }

    fmt.Printf("The 'reply' pointer value has been changed to: %s",
    reply)
    }


    Here is the Ruby code I'm attempting to use:

    require "socket"
    require "json"


    socket = TCPSocket.new "localhost", "8080"


    b = {
    method: "Compose.Details",
    params: "foobar"
    }


    socket.write(JSON.dump(b))


    resp = JSON.load(socket.readline)


    p resp


    The reason I think it doesn't work is because the Go RPC requires a
    pointer to be provided as the second argument to the exposed RPC function
    but I'm not sure how that works in a different programming language such as
    Ruby?

    I've also tried utilising a library such as
    https://github.com/chriskite/jimson

    require "jimson"


    client = Jimson::Client.new("localhost:8080")
    result = client.Details("foobar")


    But all I get back is:

    RestClient::ServerBrokeConnection: Server broke connection
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedFeb 15, '16 at 12:39p
activeFeb 18, '16 at 10:01a
posts7
users3
websitegolang.org

People

Translate

site design / logo © 2021 Grokbase