WebSocket的发送/接收是否是线程安全的(go例程安全的)?

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

Is websocket Send/Receive thread-safe (go routine-safe)?

问题

当在GO中编写一个websocket服务器时(在我的情况下使用JSON编解码器),在同一个连接上处理发送和接收数据的两个不同的Go例程是否安全?

由于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")
}
英文:

When writing a websocket server in GO (in my case using the JSON codec), is it safe to have two different Go routines for handling sending and receiving of data on the same connection?

Since websocket.JSON.Receive pauses and waits to receive data, I thought a separate Go routine for handling sending of data would be a working solution unless concurrent sending/receiving is not possible on the same connection.

So, is the working example below bad practice?

package main

import (
	&quot;fmt&quot;
	&quot;net/http&quot;
	&quot;code.google.com/p/go.net/websocket&quot;
)

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, &amp;in)

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

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

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

答案1

得分: 13

是的,您可以同时在websocket连接上调用Send、Receive和Close,就像在Go中可以使用所有net.Conn一样。以下是官方文档的一小段摘录:

> 多个goroutine可以同时调用Conn上的方法。

此外,websocket包还引入了一些编解码器,用于原子地发送/写入消息或JSON数据,这些数据可能占用多个帧。如果您查看源代码,可以看到Codec类型的Send和Receive方法将保持读取或写入锁定。

英文:

Yes, you can call Send, Receive and Close on a websocket connection concurrently, like you can with all net.Conn's in Go. A short excerpt from the official docs:

> Multiple goroutines may invoke methods on a Conn simultaneously.

Additionally, the websocket package also introduces some Codecs for sending / writing Messages or JSON data that might occupy multiple frames atomically. If you look at the source, you can see that the Send and Receive method of the Codec type will hold either the read or the write lock.

答案2

得分: 1

并发

连接支持一个并发的读取器和一个并发的写入器。

应用程序负责确保不超过一个goroutine同时调用写入方法(NextWriter,SetWriteDeadline,WriteMessage,WriteJSON,EnableWriteCompression,SetCompressionLevel),并且不超过一个goroutine同时调用读取方法(NextReader,SetReadDeadline,ReadMessage,ReadJSON,SetPongHandler,SetPingHandler)。

Close和WriteControl方法可以与所有其他方法同时调用。

英文:

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

Concurrency

Connections support one concurrent reader and one concurrent writer.

Applications are responsible for ensuring that no more than one goroutine calls the write methods (NextWriter, SetWriteDeadline, WriteMessage, WriteJSON, EnableWriteCompression, SetCompressionLevel) concurrently and that no more than one goroutine calls the read methods (NextReader, SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler) concurrently.

The Close and WriteControl methods can be called concurrently with all other methods.

huangapple
  • 本文由 发表于 2012年6月12日 03:03:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/10986008.html
匿名

发表评论

匿名网友

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

确定