• 双向通讯
    • Server

    双向通讯

    示例: bidirectional

    在正常情况下, 客户端发送请求,服务器返回结果,这样一问一答的方式就是request-response rpc 模型。

    但是对于一些用户, 比如 IoT 的开发者, 可能需要在某些时候发送通知给客户端。 如果客户端和服务端都配两套代码就显得多余和臃肿了。

    rpcx实现了一个简单的通知机制。

    首先你需要缓存客户端的连接,可能还需要将用户的ID和连接进行关联, 以便服务器知道将通知发送给哪个客户端。

    Server

    服务器使用SendMessage方法发送通知, 数据是[]byte类型。 你可以设置 servicePathserviceMethod以便提供给客户端更多的信息,用来区分不同的通知。

    net.Conn 对象可以在客户端调用服务的时候从ctx.Value(server.RemoteConnContextKey)中获取。

    1. func (s *Server) SendMessage(conn net.Conn, servicePath, serviceMethod string, metadata map[string]string, data []byte) error

    ```go server.go
    func main() {
    flag.Parse()

    1. ln, _ := net.Listen("tcp", ":9981")
    2. go http.Serve(ln, nil)
    3. s := server.NewServer()
    4. //s.RegisterName("Arith", new(example.Arith), "")
    5. s.Register(new(Arith), "")
    6. go s.Serve("tcp", *addr)
    7. for !connected {
    8. time.Sleep(time.Second)
    9. }
    10. fmt.Printf("start to send messages to %s\n", clientConn.RemoteAddr().String())
    11. for {
    12. if clientConn != nil {
    13. err := s.SendMessage(clientConn, "test_service_path", "test_service_method", nil, []byte("abcde"))
    14. if err != nil {
    15. fmt.Printf("failed to send messsage to %s: %v\n", clientConn.RemoteAddr().String(), err)
    16. clientConn = nil
    17. }
    18. }
    19. time.Sleep(time.Second)
    20. }

    }

    1. ## Client
    2. 你必须使用 `NewBidirectionalXClient` 创建 XClient 客户端, 你需要传如一个channel 这样你就可以从channel中读取通知了。
    3. ```go client.go
    4. func main() {
    5. flag.Parse()
    6. ch := make(chan *protocol.Message)
    7. d := client.NewPeer2PeerDiscovery("tcp@"+*addr, "")
    8. xclient := client.NewBidirectionalXClient("Arith", client.Failtry, client.RandomSelect, d, client.DefaultOption, ch)
    9. defer xclient.Close()
    10. args := &example.Args{
    11. A: 10,
    12. B: 20,
    13. }
    14. reply := &example.Reply{}
    15. err := xclient.Call(context.Background(), "Mul", args, reply)
    16. if err != nil {
    17. log.Fatalf("failed to call: %v", err)
    18. }
    19. log.Printf("%d * %d = %d", args.A, args.B, reply.C)
    20. for msg := range ch {
    21. fmt.Printf("receive msg from server: %s\n", msg.Payload)
    22. }
    23. }