Why doesn't the for loop cause infinite loop in this web app?

agolangf · · 563 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<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 ( &#34;github.com/gorilla/websocket&#34; &#34;net/http&#34; &#34;fmt&#34; ) 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(&#34;Start&#34;); messageType, p, err := conn.ReadMessage() // This line exit the for loop, but WHY? if err != nil { fmt.Printf(&#34;Error in read&#34;); return } err = conn.WriteMessage(messageType, p); if err != nil { fmt.Printf(&#34;Error in write&#34;); return } fmt.Printf(&#34;End&#34;); } } func main() { http.HandleFunc(&#34;/echo&#34;, echoHandler) http.Handle(&#34;/&#34;, http.FileServer(http.Dir(&#34;.&#34;))) err := http.ListenAndServe(&#34;:8080&#34;, nil) if err != nil { panic(&#34;Error: &#34; + err.Error()) } } </code></pre> <p>We see that the for loop doesn&#39;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&#39;t understand why</p> <p>The <a href="https://godoc.org/github.com/gorilla/websocket#Conn.ReadMessage" rel="nofollow">doc</a> didn&#39;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&#39;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&#39;s happening is that ReadMessage() is not &#34;breaking&#34; out of your loop. It&#39;s just a blocking call. It&#39;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 &#34;Error in read&#34; and return leaving both the for loop and the whole function.</p> <p>Here&#39;s a slightly tweaked version of the code you submitted that makes debugging this a little easier:</p> <pre><code>package main import ( &#34;fmt&#34; &#34;log&#34; &#34;net/http&#34; &#34;github.com/gorilla/websocket&#34; ) 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(&#34;error creating ugrader&#34;, err) return } for i := 0; ; i++ { fmt.Printf(&#34;Start iteration %d\n&#34;, i) messageType, p, err := conn.ReadMessage() // // This line is blocking if err != nil { fmt.Println(&#34;Error in read &#34;, err) return } fmt.Println(&#34;Recieved message: &#34;, string(p)) err = conn.WriteMessage(messageType, p) if err != nil { fmt.Println(&#34;Error in write &#34;, err) return } fmt.Println(&#34;End&#34;) } } func main() { fmt.Println(&#34;starting&#34;) http.HandleFunc(&#34;/echo&#34;, echoHandler) http.Handle(&#34;/&#34;, http.FileServer(http.Dir(&#34;.&#34;))) err := http.ListenAndServe(&#34;:8080&#34;, nil) if err != nil { panic(&#34;Error: &#34; + 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&#39;s my first message End Start iteration 1 Recieved message: here&#39;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&#39;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&#39;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 &#34;checkOrigin&#34; code in gorilla/websocket/server.go for the websocket client to work. I&#39;m testing on Go 1.6 x64 on Windows 10 x64.</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

563 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传