在ws循环中比较不断变化的变量。

huangapple go评论93阅读模式
英文:

(Go) Comparing everchanging variable in ws loop

问题

正在处理接收消息并相应处理的循环,基本上是一个带有保持活动和身份验证的 WebSocket 回显器,并且我在保持活动部分卡住了一段时间。

概念很简单,当服务器启动时,我使用一个定时器创建一个 goroutine,并初始化一个 uint64 指针。每当定时器滴答一次(每 2 秒一次),我使用 atomic.AddUint64(clockTicks, 1) 增加指针的值。然后对于每个 WebSocket 连接的 goroutine,我使用 compare 和 atomic.LoadUint64(clockTicks) 每次滴答都检查该变量,并发送一个 ping/pong 消息。

编辑:似乎有些东西阻塞了 for 循环,直到接收到消息,结果如下:

i := atomic.LoadUint64(clockTicks)
	if i != cur {
		cur = i
		if act != true {
			fmt.Println("Quit Nao U filthy bot.")
			return
		} else {
			fmt.Println("Keep Going.")
			act = false
		}
	}

在这个片段中,i := atomic.LoadUint64(clockTicks) 和整个 if 块只在发送消息时运行(在消息上打印"Keep Going."),这不是我想要的。我希望这个片段在每次迭代时运行,并且"Keep Going."和"Quit nao ..."在每次 clockTicks 增加时触发。

以下是重要的代码部分,我正在使用 Go 和 Gorilla 的 Websockets 库:

func Clock() {
clockTicks = new(uint64)
*clockTicks = 0
clock := time.NewTicker(authIntervals).C
for {
	<-clock
	atomic.AddUint64(clockTicks, 1)
}
}

var wsu = websocket.Upgrader{
ReadBufferSize:  1024,
WriteBufferSize: 1024,
CheckOrigin:     OriginHandler,
}

func serveWS(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" {
    http.Error(w, "Method not allowed", 405)
    return
}

ws, err := wsu.Upgrade(w, r, nil)
if err != nil {
	fmt.Println(err)
	return
}

defer ws.Close()
cur := atomic.LoadUint64(clockTicks)
var act, val = true, false
for {
	i := atomic.LoadUint64(clockTicks)
	if i != cur { /* 只在接收到消息时触发 */
		cur = i
		if act != true {
			fmt.Println("Quit Nao U filthy bot.")
			return
		} else {
			fmt.Println("Keep Going.")
			act = false
		}
	}

	mtype, p, err := ws.ReadMessage()
	if err != nil {
		return
	}

    ...
    
}

编辑 2:IRC 上的某人建议可能是 ws.ReadMessage 阻塞了,但我不太确定(他说 ws.ReadMessage 实现中使用的 ioutil.ReadAll 阻塞了它,他对此非常确定)。

英文:

Working on a loop that receives messages and processes them accordingly, basically a websocket echo-er with keep-alives and authentication, and I've been stuck in the keep-alive part for a little while now.

The concept is simple, when the server starts I create a goroutine with a ticker, and I initialize a uint64 pointer, each time that ticker ticks (every 2 seconds), I increment the pointer with atomic.AddUint64(clockTicks, 1), then for each websocket connection goroutine, I check the variable every tick with a compare and atomic.LoadUint64(clockTicks), and I send a ping/pong message.

Edit: Seems like something is blocking the for loop until a message is received, result:

i := atomic.LoadUint64(clockTicks)
	if i != cur {
		cur = i
		if act != true {
			fmt.Println(&quot;Quit Nao U filthy bot.&quot;)
			return
		} else {
			fmt.Println(&quot;Keep Going.&quot;)
			act = false
		}
	}

In this snippet, i := atomic.LoadUint64(clockTicks) & all the if block only runs when i message is sent (Prints "Keep Going." on msg), which is not what I want, I want the snippet to run every for iteration, and "Keep Going." & "Quit nao ..." to trigger everytime clockTicks is incremented

Here's the important code parts, I'm using Go and Gorilla's Websockets library:

func Clock() {
clockTicks = new(uint64)
*clockTicks = 0
clock := time.NewTicker(authIntervals).C
for {
	&lt;-clock
	atomic.AddUint64(clockTicks, 1)
}
}

var wsu = websocket.Upgrader{
ReadBufferSize:  1024,
WriteBufferSize: 1024,
CheckOrigin:     OriginHandler,
}

func serveWS(w http.ResponseWriter, r *http.Request) {
if r.Method != &quot;GET&quot; {
    http.Error(w, &quot;Method not allowed&quot;, 405)
    return
}

ws, err := wsu.Upgrade(w, r, nil)
if err != nil {
	fmt.Println(err)
	return
}

defer ws.Close()
cur := atomic.LoadUint64(clockTicks)
var act, val = true, false
for {
	i := atomic.LoadUint64(clockTicks)
	if i != cur { /* Only triggers when I receive a msg */
		cur = i
		if act != true {
			fmt.Println(&quot;Quit Nao U filthy bot.&quot;)
			return
		} else {
			fmt.Println(&quot;Keep Going.&quot;)
			act = false
		}
	}

	mtype, p, err := ws.ReadMessage()
	if err != nil {
		return
	}

    ...
    
}

Edit 2: Someone in IRC suggested that maybe ws.ReadMessage is blocking, but I'm not really sure (He says ioutil.ReadAll used in ws.ReadMessage implementation is blocking it, and he's pretty sure about it)

答案1

得分: 4

websocket的读取方法调用网络连接的Read方法来从网络中获取数据。由于网络连接的Read方法会阻塞,所以websocket的方法也会阻塞。

要发送ping消息,可以在写入循环中使用一个ticker,就像Gorilla聊天示例中的做法一样,或者可以为ping消息运行一个单独的goroutine,就像Gorilla命令示例中的做法一样。

英文:

The websocket read methods call the network connection Read method to get data from the network. Because the network connection Read method blocks, the webscocket methods also block.

To send pings, use a ticker in the write loop as in the Gorilla chat example or run a separate goroutine for pings as in Gorilla command example.

huangapple
  • 本文由 发表于 2015年11月2日 02:41:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/33465788.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定