2012-06-11 58 views
6

在GO中編寫websocket服務器(在我的情況下使用JSON編解碼器)時,是否可以安全地使用兩個不同的Go例程來處理在同一連接上發送和接收數據?Websocket發送/接收線程安全(去例行安全)?

由於websocket.JSON.Receive暫停並等待接收數據,我認爲一個獨立的Go例程用於處理數據發送將是一個工作的解決方案,除非在同一連接上不能同時發送/接收。

那麼,下面的工作實例是不好的做法?

package main 

import (
    "fmt" 
    "net/http" 
    "code.google.com/p/go.net/websocket" 
) 

const queueSize = 20 

type Input struct { 
    Cmd string 
} 

type Output struct { 
    Cmd string 
} 

func Handler(ws *websocket.Conn) { 

    msgWrite := make(chan *Output, queueSize) 
    var in Input 

    go writeHandler(ws, msgWrite) 

    for { 

     err := websocket.JSON.Receive(ws, &in) 

     if err != nil { 
      fmt.Println(err) 
      break 
     } else { 
      msgWrite <- &Output{Cmd: "Thanks for your message: " + in.Cmd} 
     } 
    } 
} 

func writeHandler(ws *websocket.Conn, out chan *Output) { 
    var d *Output 
    for { 
     select { 
     case d = <-out: 
      if err := websocket.JSON.Send(ws, &d); err != nil { 
       fmt.Println(err.Error()) 
      } else { 
       fmt.Println("> ", d.Cmd) 
      } 
     } 
    } 
} 

func main() { 
    http.Handle("/echo", websocket.Handler(Handler)); 
    err := http.ListenAndServe(":1235", nil); 
    if err != nil { 
     panic("ListenAndServe: " + err.Error()) 
    } 
    fmt.Println("Server running") 
} 

回答

9

是的,你可以打電話發,在全力以赴net.Conn的接收和關閉一個WebSocket連接上同時一樣可以。官方文檔的簡短摘錄:

多個goroutines可能同時調用Conn上的方法。

此外,websocket軟件包還引入了一些編解碼器,用於發送/寫入可能以原子方式佔用多個幀的消息或JSON數據。如果您查看源代碼,您可以看到Codec類型的Send和Receive方法將保存讀取或寫入鎖定。

+0

感謝您的解決方案!我錯過了查看網絡包的答案,所以我很高興你指出。 – ANisus

+0

@ tux21b你在哪裏看到它會嘗試組合多個幀來形成單個json消息?我沒有在源代碼和註釋中看到它沒有指出它的方法:「//接收從ws__接收__single幀,由cd.Unmarshal解組並存儲在v中。」強調我的。 – Aktau

0

http://www.gorillatoolkit.org/pkg/websocket

併發報價

連接支持一個併發的讀寫器和一個並行的作家。 (NextWriter,SetWriteDeadline,WriteMessage,WriteJSON,EnableWriteCompression,SetCompressionLevel)並且不超過一個goroutine調用讀取方法(NextReader,SetReadDeadline,ReadMessage ,ReadJSON,SetPongHandler,SetPingHandler)。

Close和WriteControl方法可以與所有其他方法同時調用。