Go

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

发布于 2021-02-01 11:01:27

使用net/rpcGo中的软件包,实际上是否可以从服务器向客户端进行RPC调用?如果没有,是否有更好的解决方案?

关注者
0
被浏览
103
1 个回答
  • 面试哥
    面试哥 2021-02-01
    为面试而生,有面试问题,就找面试哥。

    我目前正在使用Thriftthrift4go)来实现服务器->客户端和客户端->服务器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();
    }
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看