【问题标题】:grpc go : how to know in server side, when client closes the connectiongrpc go:如何在服务器端知道客户端何时关闭连接
【发布时间】:2017-02-11 01:08:50
【问题描述】:

我正在使用 grpc go

我有一个大致像这样的 rpc

196 service MyService {
197   // Operation 1
198   rpc Operation1(OperationRequest) returns (OperationResponse) {
199       option (google.api.http) = {
200         post: "/apiver/myser/oper1"
201         body: "*"
202     };
203   }

客户端使用 grpc.Dial() 方法连接

当客户端连接时,服务器会做一些记录。当客户端断开连接时,需要删除簿记。

是否有任何可以注册的回调可以用来知道客户端已经关闭了会话。

【问题讨论】:

  • 我自己还没有使用过 gRPC,但我很快就会使用,在我的研究过程中,我看到服务器接口方法传递了一个 ctx context.Context 参数。我想假设如果与客户端的连接关闭,此上下文将被取消。见Go gRPC Basics
  • 感谢您的评论!!。我已经探索了ctx.Done() 选项。此通道在每次操作时关闭,在同一连接上。那不是我要找的。我正在寻找一个通道来读取连接关闭事件。
  • 在我们的 rpc 应用程序中,我们定期使用 time.Ticker 进行轮询,调用状态函数,如果返回连接错误,我们从 master 端将 worker 标记为已死。不确定这是否适合您的用例。

标签: go grpc


【解决方案1】:

根据您的代码,这是一个一元 rpc 调用,客户端仅连接一次服务器,发送请求并获得响应。客户端将等待响应直到超时。

在服务器端流式传输中,您可以让客户端断开连接

<-grpc.ServerStream.Context.Done()

信号。

通过上述方法,您可以在 go 例程中实现自己的通道来构建您的逻辑。使用select 语句作为:

select {
    case <-srv.Context().Done():
        return
    case res := <-<YOUR OWN CHANNEL, WITH RECEIVED RESQUEST OR YOUR RESPONSE>
        ....
}

我提供一些详细代码here

在客户端流式传输中,除了上述信号外,您还可以检查服务器是否可以接收到消息:

req, err := grpc.ServerStream.Recv()
if err == io.EOF {
    break
} else if err != nil {
    return err
}

【讨论】:

  • 你的Stream.Context.Done()救了我的命!!!!
  • 很高兴为您提供帮助。 ^_^
【解决方案2】:

假设服务器是在 go 中实现的,*grpc.ClientConn 上有一个 API 可以报告连接中的状态变化。

func (cc *ClientConn) WaitForStateChange(ctx context.Context, sourceState connectivity.State) bool

https://godoc.org/google.golang.org/grpc#ClientConn.WaitForStateChange

这些是每个connectivity.State 上的文档

https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md

如果您需要公开一个可以收听客户端关闭连接的频道,那么您可以执行以下操作:

func connectionOnState(ctx context.Context, conn *grpc.ClientConn, states ...connectivity.State) <-chan struct{} {
    done := make(chan struct{})

    go func() {
        // any return from this func will close the channel
        defer close(done)

        // continue checking for state change 
        // until one of break states is found
        for { 
            change := conn.WaitForStateChange(ctx, conn.GetState())
            if !change {
                // ctx is done, return
                // something upstream is cancelling
                return
            }

            currentState := conn.GetState()

            for _, s := range states {
                if currentState == s {
                    // matches one of the states passed
                    // return, closing the done channel
                    return 
                }
            }
        }
    }()

    return done
}

如果您只想考虑正在关闭或关闭的连接,那么您可以这样称呼它:

// any receives from shutdownCh will mean the state Shutdown
shutdownCh := connectionOnState(ctx, conn, connectivity.Shutdown) 

【讨论】:

  • 您的解决方案不只是针对客户端吗?我以为 OP 是在询问如何在服务器端知道。
【解决方案3】:

作为github问题:link 你可以这样做

err = stream.Context().Err()
if err != nil {
    break
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-06
    • 1970-01-01
    • 1970-01-01
    • 2019-01-22
    • 1970-01-01
    • 2020-04-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多