为了账号安全,请及时绑定邮箱和手机立即绑定

Go中来自客户端和服务器的RPC

Go中来自客户端和服务器的RPC

Go
一只斗牛犬 2021-04-26 17:43:17
使用net/rpcGo中的软件包,实际上是否可以从服务器向客户端进行RPC调用?如果没有,是否有更好的解决方案?
查看完整描述

3 回答

?
沧海一幻觉

TA贡献1824条经验 获得超5个赞

我目前正在使用thrift(thrift4go)来实现服务器->客户端和客户端->服务器RPC功能。默认情况下,thrift仅像net / rpc一样执行客户端->服务器调用。由于还需要服务器与客户机之间的通信,因此我进行了一些研究,发现bidi-thrift。Bidi-thrift解释了如何连接Java服务器+ Java客户端进行双向节俭通信。


比迪蒂节俭是做什么的,它的局限性。

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


解决方案

我改变了“比迪节约”的概念,使客户端打开了到服务器的两个连接,即A和B。第一个连接(A)用于执行客户端->服务器通信(客户端照常进行呼叫)。第二个连接(B)被“劫持”,并且连接到客户端上的服务器(处理器),而第二个连接(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()

        }()

    }

}

Java客户端

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

}


查看完整回答
反对 回复 2021-05-17
?
SMILET

TA贡献1796条经验 获得超4个赞

RPC是一项(远程)服务。每当某些计算机请求远程服务时,它就充当客户端,要求服务器提供该服务。在此“定义”中,服务器调用客户端RPC的概念没有明确定义的含义。


查看完整回答
反对 回复 2021-05-17
  • 3 回答
  • 0 关注
  • 194 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信