grpc-go,双向流模式中服务器主动关闭stream

在grpc的编码中发现客户端stream流有方法。CloseSend() error

客户端如果想主动关闭连接直接调用此方法即可关闭,但是服务端对应的ServerStream没有关闭的方法,最后Google一下发现github grpc 项目中有对应的解答:https://github.com/grpc/grpc-go/issues/444

很简单服务端只需要跳出循环即可断开连接,下面贴出我的解决方案:

主动关闭的方法,向chan发送标志位。

func (s *Grpc_session) Close() {
	close(s.WriteChan)
	// 没有找到Serverstream关闭的方法,只能发送chan退出循环
	s.exit <- true
}

这里直接用select接受chan,如果接受到则退出。

func DoWithTimeout(f func() (*Message, error), d time.Duration) (*Message, error) {
	errChan := make(chan error, 1)
	Message := make(chan *Message, 1)
	go func() {
		message, err := f()
		if err != nil {
			errChan <- err
		} else {
			Message <- message
		}
		//close(errChan)
	}()
	t := time.NewTimer(5 * time.Second)
	select {
	case <-t.C:
		return nil, fmt.Errorf("slow")
	case err := <-errChan:
		if !t.Stop() {
			<-t.C
			return nil, err
		}
	case message := <-Message:
		return message, nil

	}
	return nil, fmt.Errorf("slow")
}

func (s *Grpc_session) Run() error {
	for {
		select {
		case <-s.exit:
			return nil
		default:

			//in, err := s.Comminute_client.Recv()
	in, err := DoWithTimeout(func() (*Message, error) { return stream.Recv() }, 5*time.Second)
			if err == io.EOF {
				fmt.Println("read done")
				return nil
			}
			if err != nil {
				fmt.Errorf("ERROR : %v", err)
				return err
			}

			f, exit := func_manage.FunManage.Get(in.GetName())
			if exit != nil {
				fmt.Errorf("%v has not Register!", in.GetName())
				continue
			}
			switch f.(type) {
			case func(...interface{}):
				go f.(func(...interface{}))(in, s)
			case func(...interface{}) interface{}:
			case func(...interface{}) []interface{}:
			default:
				fmt.Println("function id : definition of function is invalid")
			}

		}
	}

}

在测试中,退出循环时客户端也收到服务端断开连接的标志,证明方案可行~~

你可能感兴趣的:(Go,Grpc)