实际上是否可以使用Go中的net/rpc
包从服务器到客户端进行RPC调用?如果不是,那里有更好的解决方案吗?
答案 0 :(得分:5)
我目前正在使用thrift(thrift4go)来获取server->客户端和客户端>服务器RPC功能。默认情况下,thrift只执行客户端>服务器调用,就像net / rpc一样。由于我还需要服务器 - >客户端通信,我做了一些研究并找到了bidi-thrift。 Bidi-thrift解释了如何连接java服务器+ java客户端以进行双向thrift通信。
TCP连接具有接收和传出通信线路(RC和TX)。 bidi-thrift的想法是拆分RS和TX,并将它们提供给客户端应用程序和服务器应用程序上的服务器(处理器)和客户端(远程)。我发现在Go中很难做到这一点。此外,这种方式不存在“响应”(响应线正在使用中)。因此,服务中的所有方法都必须“单向无效”。 (火与忘记,召唤没有结果)。
我改变了bidi-thrift的想法并使客户端打开了两个与服务器A和B的连接。第一个连接(A)用于执行客户端 - >服务器通信(客户端像往常一样进行呼叫)。第二个连接(B)被'劫持',并连接到客户端上的服务器(处理器),同时连接到服务器上的客户端(远程)。我使用Go服务器和Java客户端。它工作得很好。它快速可靠(就像正常的节俭一样)。
某些来源.. B连接(服务器 - >客户端)设置如下:
// factories
framedTransportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory())
protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
// create socket listener
addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:9091")
if err != nil {
log.Print("Error resolving address: ", err.Error(), "\n")
return
}
serverTransport, err := thrift.NewTServerSocketAddr(addr)
if err != nil {
log.Print("Error creating server socket: ", err.Error(), "\n")
return
}
// Start the server to listen for connections
log.Print("Starting the server for B communication (server->client) on ", addr, "\n")
err = serverTransport.Listen()
if err != nil {
log.Print("Error during B server: ", err.Error(), "\n")
return //err
}
// Accept new connections and handle those
for {
transport, err := serverTransport.Accept()
if err != nil {
return //err
}
if transport != nil {
// Each transport is handled in a goroutine so the server is availiable again.
go func() {
useTransport := framedTransportFactory.GetTransport(transport)
client := worldclient.NewWorldClientClientFactory(useTransport, protocolFactory)
// Thats it!
// Lets do something with the connction
result, err := client.Hello()
if err != nil {
log.Printf("Errror when calling Hello on client: %s\n", err)
}
// client.CallSomething()
}()
}
}
// preparations for B connection
TTransportFactory transportFactory = new TTransportFactory();
TProtocolFactory protocolFactory = new TBinaryProtocol.Factory();
YourServiceProcessor processor = new YourService.Processor<YourServiceProcessor>(new YourServiceProcessor(this));
/* Create thrift connection for B calls (server -> client) */
try {
// create the transport
final TTransport transport = new TSocket("127.0.0.1", 9091);
// open the transport
transport.open();
// add framing to the transport layer
final TTransport framedTransport = new TFramedTransport(transportFactory.getTransport(transport));
// connect framed transports to protocols
final TProtocol protocol = protocolFactory.getProtocol(framedTransport);
// let the processor handle the requests in new Thread
new Thread() {
public void run() {
try {
while (processor.process(protocol, protocol)) {}
} catch (TException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
}
}.start();
} catch(Exception e) {
e.printStackTrace();
}
答案 1 :(得分:2)
我遇到了实现它的rpc2。一个例子:
Server.go
// server.go
package main
import (
"net"
"github.com/cenkalti/rpc2"
"fmt"
)
type Args struct{ A, B int }
type Reply int
func main(){
srv := rpc2.NewServer()
srv.Handle("add", func(client *rpc2.Client, args *Args, reply *Reply) error{
// Reversed call (server to client)
var rep Reply
client.Call("mult", Args{2, 3}, &rep)
fmt.Println("mult result:", rep)
*reply = Reply(args.A + args.B)
return nil
})
lis, _ := net.Listen("tcp", "127.0.0.1:5000")
srv.Accept(lis)
}
Client.go
// client.go
package main
import (
"fmt"
"github.com/cenkalti/rpc2"
"net"
)
type Args struct{ A, B int }
type Reply int
func main(){
conn, _ := net.Dial("tcp", "127.0.0.1:5000")
clt := rpc2.NewClient(conn)
clt.Handle("mult", func(client *rpc2.Client, args *Args, reply *Reply) error {
*reply = Reply(args.A * args.B)
return nil
})
go clt.Run()
var rep Reply
clt.Call("add", Args{5, 2}, &rep)
fmt.Println("add result:", rep)
}
答案 2 :(得分:1)
RPC是一种(远程)服务。每当某台计算机请求远程服务时,它就会充当客户端,要求服务器提供服务。在这个“定义”中,服务器调用客户端RPC的概念没有明确定义的含义。