grpc go:当客户端关闭连接时,如何知道服务器端

时间:2016-10-03 06:30:48

标签: go grpc

我正在使用grpc go

我有一个看起来大致像这样的rpc

<script>
$(function() {
  var itm = [];
$( "#savebutton" ).click(function() { LISTOBJ.saveList(); });
  $("#myAccordion").accordion({
    heightStyle: "content",
    active: false,
    collapsible: true
  });
  $("#myAccordion li").draggable({
    appendTo: "body",
    helper: "clone"
  });
  $(".leader ol").droppable({
    activeClass: "ui-state-default",
    hoverClass: "ui-state-hover",
    accept: ":not(.ui-sortable-helper)",
    drop: function(event, ui) {
      var zz = ui.draggable.text()
      var xyz = itm.includes(zz);
      if (xyz === false) {
        $(this).find(".placeholder").remove();
        $("<li></li>").text(ui.draggable.text())
          //.addClass("cart-item")
          .addClass('dropClass')
          .appendTo(this);

        //add to array
        itm.push(zz);
        //add style
        //$('.ui-droppable').find("li.ui-draggable:contains('" + zz + "')").addClass('bred');
        var n = $(this).closest("div.proc").find(".dropClass").length;
        $(this).closest("div.proc").find("span").text("Items Dropped: " + n + ".");

      } else {
        alert('Name is Already Exist');
      }

    }
  }).sortable({
    items: "li:not(.placeholder)",
    sort: function() {
      $(this).removeClass("ui-state-default");
    }
  });
  $(".checker ol").droppable({
    activeClass: "ui-state-default",
    hoverClass: "ui-state-hover",
    accept: ":not(.ui-sortable-helper)",
    drop: function(event, ui) {
      var zz = ui.draggable.text()
      var xyz = itm.includes(zz);
      if (xyz === false) {
        $(this).find(".placeholder").remove();
        $("<li></li>").text(ui.draggable.text())
          //.addClass("cart-item")
          .addClass('dropClass')
          .appendTo(this);

        //add to array
        itm.push(zz);
        //add style
        $('.ui-droppable').find("li.ui-draggable:contains('" + zz + "')").addClass('bred');
        var n = $(this).closest("div.proc").find(".dropClass").length;
        $(this).closest("div.proc").find("span").text("Items Dropped: " + n + ".");

      } else {
        alert('Name is Already Exist');
      }

    }
  }).sortable({
    items: "li:not(.placeholder)",
    sort: function() {
      $(this).removeClass("ui-state-default");
    }
  });
  $("#myAccordion ul").droppable({
    drop: function(event, ui) {
      $(ui.draggable).remove();
      var zz = ui.draggable.text()
      $('.ui-droppable').find("li.ui-draggable:contains('" + zz + "')").removeClass('bred');

      var indexItm = itm.indexOf(zz);
      if (indexItm > -1) {
        itm.splice(indexItm, 1);
      }
    },
    hoverClass: "ui-state-hover"
      //accept: '.cart-item'
  });
});
var LISTOBJ = {
    saveList: function() {
        $(".leader").each(function() {
          var listCSV = [];
          $(this).find("li").each(function(){
              listCSV.push($(this).text());
          });
          var values = listCSV.join(', ');
          $(".output").append("<input type='hidden' name='leader[]' value='"+values+"' />");
          $("#output").append("<p>"+values+"</p>");
              console.debug(listCSV);
        });
    }
}
</script>

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

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

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

3 个答案:

答案 0 :(得分:3)

假设服务器是在go中实现的,$(window).scroll(function() { var height = $(window).scrollTop(); if(height > some_number) { // change url here } }); 上有一个API报告连接状态更改。

*grpc.ClientConn

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

这些是每个func (cc *ClientConn) WaitForStateChange(ctx context.Context, sourceState connectivity.State) bool

上的文档

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

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

connectivity.State

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

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
}

答案 1 :(得分:2)

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

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

<-grpc.ServerStream.Context.Done()

信号。

有了上面的内容,您必须在 go 例程中实现您自己的频道来构建您的逻辑。使用 select 语句为:

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

在客户端流中,除了上面的信号,你还可以检查服务器是否可以接收到msg:

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

答案 2 :(得分:0)

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

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