dongtao4319 2012-10-31 19:15
浏览 120
已采纳

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

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?

  • 写回答

3条回答 默认 最新

  • dongluolie3487 2012-11-01 19:43
    关注

    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(), "
    ")
        return
    }
    serverTransport, err := thrift.NewTServerSocketAddr(addr)
    if err != nil {
        log.Print("Error creating server socket: ", err.Error(), "
    ")
        return
    }
    
    // Start the server to listen for connections
    log.Print("Starting the server for B communication (server->client) on ", addr, "
    ")
    err = serverTransport.Listen()
    if err != nil {
        log.Print("Error during B server: ", err.Error(), "
    ")
        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
    ", 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();
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计
  • ¥15 帮我写一个c++工程
  • ¥30 Eclipse官网打不开,官网首页进不去,显示无法访问此页面,求解决方法
  • ¥15 关于smbclient 库的使用
  • ¥15 微信小程序协议怎么写
  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教