2012-06-11 60 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方法可以与所有其他方法同时调用。