来自Go的客户端和服务器的RPC [英] RPC from both client and server in Go

查看:173
本文介绍了来自Go的客户端和服务器的RPC的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

实际上是否可以在Go中使用 net / rpc 包从服务器到客户端执行RPC调用?如果没有,有没有更好的解决方案呢?

解决方案

我目前使用的是节俭( thrift4go )用于服务器 - >客户端和客户端 - >服务器RPC功能。默认情况下,thrift只会像net / rpc一样进行客户端 - >服务器调用。因为我还需要服务器 - >客户端通信,所以我做了一些研究,发现比迪-节俭。 Bidi-thrift解释了如何连接一个java服务器+ java客户端进行双向节约通信。



什么是bidi-thrift,它是限制。



TCP连接具有输入和输出通信线(RC和TX)。 bidi-thrift的思想是将RS和TX分开,并在客户端应用程序和服务器应用程序上将这些提供给服务器(处理器)和客户端(远程)。我发现这在Go中很难做到。此外,这种方式没有响应可能(响应线正在使用)。因此,服务中的所有方法都必须是单向无效。 (火和忘记,调用没有结果)。

解决方案



我改变了bidi-使客户端打开两个连接到服务器A和B的连接。第一个连接(A)用于执行客户端 - >服务器通信(客户端像往常一样进行呼叫)。第二个连接(B)被劫持,并连接到客户端上的服务器(处理器),同时连接到服务器上的客户端(远程)。我有一个Go服务器和一个Java客户端的工作。它工作得很好。它是快速和可靠的(就像正常的节俭一样)。



有些来源.. B连接(服务器 - >客户端)是这样设置的:



Go服务器



  //工厂
framedTransportFactory:= thrift.NewTFramedTransportFactory (thrift.NewTTransportFactory())
protocolFactory:= thrift.NewTBinaryProtocolFactoryDe​​fault()

//创建套接字侦听器
addr,err:= net.ResolveTCPAddr(tcp, )
if err!= nil {
log.Print(Error resolving address:,err.Error(),\\\

return

serverTransport,err:= thrift.NewTServerSocketAddr(addr)
if err!= nil {
log.Print(Error creating server socket:,err.Error() ,\\\

返回
}

//启动服务器以侦听连接
log.Print(启动B通信服务器服务器>客户端)on,addr,\\\

err = serverTransport.Listen()
if err!= nil {
log。打印(在B服务器中出错:,err.Error(),\\\

返回//错误
}

//接受新连接并处理那些
用于{
transport,err:= serverTransport.Accept()
if err!= nil {
return // err
}
if transport != nil {
//每个传输都在goroutine中处理,所以服务器可以再次使用。
去func(){
useTransport:= framedTransportFactory.GetTransport(transport)
client:= worldclient.NewWorldClientClientFactory(useTransport,protocolFactory)

//这就是它!
//让我们用connction
结果做一些事情,err:= client.Hello()
if err!= nil {
log.Printf(Errror When calling Hello客户:%s\\\
,错误)
}

// client.CallSomething()
}()
}
}



Java客户端



  //准备B连接
TTransportFactory transportFactory = new TTransportFactory();
TProtocolFactory protocolFactory = new TBinaryProtocol.Factory();
YourServiceProcessor processor = new YourService.Processor< YourServiceProcessor>(new YourServiceProcessor(this));


创建B调用的节点连接(服务器 - >客户端)* /
尝试{
//创建传输
final TTransport transport = new TSocket(127.0.0.1,9091);

//打开运输
transport.open();

//将帧添加到传输层
final TTransport framedTransport = new TFramedTransport(transportFactory.getTransport(transport));

//将帧传输连接到协议
final TProtocol protocol = protocolFactory.getProtocol(framedTransport);

//让处理器处理新线程中的请求
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();
}


Is it actually possible to do RPC calls from a server to a client with the net/rpc package in Go? If no, is there a better solution out there?

解决方案

I am currently using thrift (thrift4go) for server->client and client->server RPC functionality. By default, thrift does only client->server calls just like net/rpc. As I also required server->client communication, I did some research and found bidi-thrift. Bidi-thrift explains how to connect a java server + java client to have bidirectional thrift communication.

What bidi-thrift does, and it's limitations.

A TCP connection has an incomming and outgoing communication line (RC and TX). The idea of bidi-thrift is to split RS and TX and provide these to a server(processor) and client(remote) on both client-application and server-application. I found this to be hard to do in Go. Also, this way there is no "response" possible (the response line is in use). Therefore, all methods in the service's must be "oneway void". (fire and forget, call gives no result).

The solution

I changed the idea of bidi-thrift and made the client open two connections to the server, A and B. The first connection(A) is used to perform client -> server communication (where client makes the calls, as usual). The second connection(B) is 'hijacked', and connected to a server(processor) on the client, while it is connected to a client(remote) on the server. I've got this working with a Go server and a Java client. It works very well. It's fast and reliable (just like normal thrift is).

Some sources.. The B connection (server->client) is set up like this:

Go server

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

Java client

// 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();
}

这篇关于来自Go的客户端和服务器的RPC的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆