我有一个用Go编写的有效的RPC TCP服务,但是当使用Ruby连接到该服务时,它挂起了,因为似乎没有数据通过打开的套接字连接发送回。
远程RPC功能:
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
}
远程RPC端点公开:
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)
}
}
通过TCP到远程RPC功能的客户端连接(使用Golang,因此我知道它至少在此方面有效):
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)
}
这是我尝试使用的Ruby代码:
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
我认为它不起作用的原因是因为Go RPC要求提供一个指针作为公开RPC函数的第二个参数,但是我不确定它如何在其他编程语言(如Ruby)中工作?
我也尝试过利用https://github.com/chriskite/jimson之类的库
require "jimson"
client = Jimson::Client.new("localhost:8080")
result = client.Details("foobar")
但是我得到的只是:
RestClient::ServerBrokeConnection: Server broke connection
因此,正如JimB在评论中指出的那样,我需要改用JSON RPC库。如您所见,事情仍然不太正常。
这是更新的Ruby客户端:
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)
随后是更新的Go客户端:
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
}
当我运行此程序时,我的Ruby客户端会看到以下内容:
{"id"=>nil, "result"=>"Blah!", "error"=>nil}
所以我得到了一个结果,但是如果我的实际RPC代码试图以任何方式使用提供的args来生成结果,那么这将是一个残破的示例,因为我从Go RPC函数获得的标准输出是一组空的arg值?
Args received: &{foo: bar:}
我不确定RPC函数为什么不能提取我提供给它的参数?
还有“ id”键:为什么我要从RPC函数中找回一个?以及如何赋予它有意义的价值?
我尝试用我的Ruby客户端中的值设置“ id”键,但这并没有影响Go RPC的响应。
好的,因此我需要在代码中进行的实际修复如下:
传入的args必须是自定义类型,因此您可以将其导出,并且该类型中的字段本身也需要导出...
type Args struct {
Foo string
Bar string
}
但更重要的是,在Ruby方面,您需要以符合此要求的格式发送JSON-> https://golang.org/src/net/rpc/jsonrpc/client.go#L45 <-happy
这样吧...
b = {
:method => "Compose.Details",
:params => [{ :Foo => "Foo!", :Bar => "Bar!" }],
:id => "0" # id is just echo'ed back to the client
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句