Go——处理用户连接超时

所谓超时,就是一段时间用户没有做出任何操作,这里需要了解 select

select

  • select 用法与 switch 语言非常类似,由 select 开始一个新的选择块,每个选择条件由 case 语句来描述

  • case 语句里必须是一个 IO 操作

  • select语句中,会按顺序从头至尾评估每一个发送和接收的语句,如果其中的任意一语句可以继续执行(即没有被阻塞),那么就从那些可以执行的语句中任意选择一条来使用

  • 如果 case 条件中都是阻塞的,那么 select 就会走 default 语句,没有 default 语句就会处于一直等待状态,直到任意一条 case 条件成立

  • 一般不建议写 default,写了话,走 default 的概率太大

  • select 一般与 for 循环搭配使用,

超时操作

  • 示例代码

    func main() {
    	ch1 := make(chan int)
    	ch2 := make(chan int)
    	go func() {
    		for {
    			<-ch1
    			fmt.Println("get ch1")
    		}
    
    	}()
    	go func() {
    		for {
    			<-ch2
    			fmt.Println("get ch2")
    		}
    	}()
    
    	for {
    		select {
    		case ch1 <- 1:
    		case ch2 <- 2:
    		case <-time.After(time.Second * 1):
    			fmt.Println("tiem out .................")
    		}
    	}
    }
    
    func main() {
    	ch1 := make(chan int)
    	ch2 := make(chan int)
    	go func() {
    		for {
    			<-ch1
    			fmt.Println("get ch1")
    		}
    
    	}()
    	go func() {
    		for {
    			<-ch2
    			fmt.Println("get ch2")
    		}
    	}()
    
    	for {
    		select {
    		case ch1 <- 1:
    		case ch2 <- 2:
    		case <-time.After(time.Microsecond * 50):
    			fmt.Println("tiem out .................")
    		}
    	}
    }
    
  • 第一段代码最后输出结果要么是 get ch1,要么是 get ch2,到最后都没看到 time out ...,这是为什么?

  • 第二段代码最后输出结果是打印多次 time out ....,这是为什么?

  • 回过头看一下 select 的定义,其中有一句话是这样的:评估每一条 case 语句,任意选择一条未阻塞的语句执行

  • 第一段代码 ch1、ch2 将数据发送到下游管道的时间,是明显短于定时器 1 秒,此时定时器相对于它们是处于阻塞状态的

  • 第二段代码 ch1、ch2、tiem 都将会被 select 考虑,因为 ch1、ch2 管道的流动速度不是每次都比定时器的 50 微秒快的

实际运用

  • 例如聊天室,当客户端连接到服务器,此时我们就开一个协程,基本代码如上,for 循环里面利用 select 不断监听管道流动,定时器时间为 20 秒

  • 20 秒钟内,其他管道都处于阻塞状态,也就是没有客户数据的流入,那么 select 将会执行定时器内的操作,操作大多是 return,结束循环,触发 defer,关闭 conn 连接

posted @ 2018-08-04 03:06  cnloop  阅读(206)  评论(0编辑  收藏  举报