<p>Consider the following example. <a href="http://41j.com/blog/2014/12/gorilla-websockets-golang-simple-websockets-example/" rel="nofollow">Reference</a></p>
<pre><code>package main
import (
"github.com/gorilla/websocket"
"net/http"
"fmt"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func echoHandler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
//log.Println(err)
return
}
for {
fmt.Printf("Start");
messageType, p, err := conn.ReadMessage() // This line exit the for loop, but WHY?
if err != nil {
fmt.Printf("Error in read");
return
}
err = conn.WriteMessage(messageType, p);
if err != nil {
fmt.Printf("Error in write");
return
}
fmt.Printf("End");
}
}
func main() {
http.HandleFunc("/echo", echoHandler)
http.Handle("/", http.FileServer(http.Dir(".")))
err := http.ListenAndServe(":8080", nil)
if err != nil {
panic("Error: " + err.Error())
}
}
</code></pre>
<p>We see that the for loop doesn't have any condition, so it loops forever, but when I hit the <code>/echo</code> API, <code>Start</code> only gets print twice and <code>End</code> only get print once. And there are no error printing. </p>
<p>I found out that the loop is exit in </p>
<pre><code>conn.ReadMessage()
</code></pre>
<p>but I don't understand why</p>
<p>The <a href="https://godoc.org/github.com/gorilla/websocket#Conn.ReadMessage" rel="nofollow">doc</a> didn't mention any <code>break</code></p>
<p>Can someone give me some insight?</p>
<hr/>**评论:**<br/><br/>PsyWolf: <pre><p>Your intuition was right although technically it's not a totally infinite loop. That code cannot leave the for loop <strong><em>unless</em></strong> one of those functions returns an error. In fact, if you try to put any code directly after the for loop, go vet will tell you that it is unreachable.</p>
<p>What's happening is that ReadMessage() is not "breaking" out of your loop. It's just a blocking call. It's waiting for next request to come in or for the connection to be closed by the client. In other words, ReadMessage() does 2 things: first it waits for a message, then it reads it. Alternatively, when the client closes the connection, ReadMessage() will return a non-nil error. That will cause your code to print "Error in read" and return leaving both the for loop and the whole function.</p>
<p>Here's a slightly tweaked version of the code you submitted that makes debugging this a little easier:</p>
<pre><code>package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
func echoHandler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("error creating ugrader", err)
return
}
for i := 0; ; i++ {
fmt.Printf("Start iteration %d\n", i)
messageType, p, err := conn.ReadMessage() // // This line is blocking
if err != nil {
fmt.Println("Error in read ", err)
return
}
fmt.Println("Recieved message: ", string(p))
err = conn.WriteMessage(messageType, p)
if err != nil {
fmt.Println("Error in write ", err)
return
}
fmt.Println("End")
}
}
func main() {
fmt.Println("starting")
http.HandleFunc("/echo", echoHandler)
http.Handle("/", http.FileServer(http.Dir(".")))
err := http.ListenAndServe(":8080", nil)
if err != nil {
panic("Error: " + err.Error())
}
}
</code></pre>
<p>and the output from opening some connections and sending some messages is</p>
<pre><code>starting
Start iteration 0
Recieved message: here's my first message
End
Start iteration 1
Recieved message: here's my 2nd message
End
Start iteration 2
Recieved message: and a third, about to close
End
Start iteration 3
Error in read websocket: close 1005 (no status)
Start iteration 0
Recieved message: first message on 2nd connection
End
Start iteration 1
Recieved message: closing now
End
Start iteration 2
Error in read websocket: close 1005 (no status)
</code></pre></pre>katandkit: <pre><p>Oh that makes so much sense.</p>
<p>Thank you for the explanation.</p></pre>jcbwlkr: <pre><p>Don't just print that there was an error, print the err variable itself and see what it says</p></pre>motojo: <pre><p>The for loop does not break for me. I'm testing using this Chrome plugin: <a href="https://chrome.google.com/webstore/detail/simple-websocket-client/pfdhoblngboilpfeibdedpjgfnlcodoo?hl=en" rel="nofollow">https://chrome.google.com/webstore/detail/simple-websocket-client/pfdhoblngboilpfeibdedpjgfnlcodoo?hl=en</a></p>
<p>I just had to disable the "checkOrigin" code in gorilla/websocket/server.go for the websocket client to work. I'm testing on Go 1.6 x64 on Windows 10 x64.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传