如何从Go WebSocket处理程序访问其他客户端连接?

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

How to access other client connections from a Go WebSocket handler?

问题

注意:我更感兴趣的是理解Go的一般概念/模式,而不是解决这个人为的例子。

Go(golang)WebSocket包提供了一个简单的回声服务器示例,可以简化为以下代码:

func EchoServer(ws *websocket.Conn) { io.Copy(ws, ws); }

func main() {
 http.Handle("/echo", websocket.Handler(EchoServer));
 http.ListenAndServe(":12345", nil);
}

该服务器处理并发连接,我想将其升级为基本的聊天服务器,通过将输入回显给所有连接的客户端。

我该如何让EchoServer处理程序能够访问每个打开的连接?

英文:

Note: I'm more interested in understanding general Go concepts/patterns, rather than solving this contrived example.

The Go (golang) WebSocket package provides a trivial echo server example, which condenses down to something like this:

func EchoServer(ws *websocket.Conn) { io.Copy(ws, ws); }

func main() {
 http.Handle("/echo", websocket.Handler(EchoServer));
 http.ListenAndServe(":12345", nil);
}

The server handles simultaneous connections, and I'm trying to upgrade it to a basic chat server by echoing the input to all connected clients.

How would I go about providing the EchoServer handler access to each of the open connections?

答案1

得分: 6

一个快速的几乎功能完整的示例,以便给你一个想法

var c = make(chan *websocket.Conn, 5) //5是一个任意的缓冲区大小
var c2 = make(chan []byte, 5)
func EchoServer(ws *websocket.Conn) {
    buff := make([]byte, 256)
    c <- ws
    for size, e := ws.Read(buff); e == nil; size, e = ws.Read(buff) {
        c2 <- buff[0:size]
    }
    ws.Close()
}
func main() {
	go func() {
		var somekindofstorage
		for {
			select {
			case newC := <-c:
				somekindofstorage.Add(newC)
			case msg := <-c2:
				for _, v := range somekindofstorage {
					if _, e := v.Write(msg); e != nil { //假设客户端在写入错误时断开连接
						somekindofstorage.Remove(v)
					}
				}
			}
		}
	}()
    http.Handle("/echo", websocket.Handler(EchoServer));
    http.ListenAndServe(":12345", nil);
}

这启动了一个goroutine,监听两个通道,一个用于添加新连接,一个用于发送消息到所有活动连接。<code>somekindofstorage</code>可以是一个map或一个vector。

编辑:

或者,你可以只将所有连接存储在全局map中,并从<code>EchoServer</code>写入每个连接。但是map不适合并发访问。

英文:

A quick little almost-functional example to give you an idea

var c = make(chan *websocket.Conn, 5) //5 is an arbitrary buffer size
var c2 = make(chan []byte, 5)
func EchoServer(ws *websocket.Conn) {
    buff := make([]byte, 256)
    c &lt;- ws
    for size, e := ws.Read(buff); e == nil; size, e = ws.Read(buff) {
        c2 &lt;- buff[0:size]
    }
    ws.Close()
}
func main() {
	go func() {
		var somekindofstorage
		for {
			select {
			case newC := &lt;-c:
				somekindofstorage.Add(newC)
			case msg := &lt;-c2:
				for _, v := range somekindofstorage {
					if _, e := v.Write(msg); e != nil { //assuming the client disconnected on write errors
						somekindofstorage.Remove(v)
					}
				}
			}
		}
	}()
    http.Handle(&quot;/echo&quot;, websocket.Handler(EchoServer));
    http.ListenAndServe(&quot;:12345&quot;, nil);
}

This starts a goroutine that listens on two channels, one for new connections to add and one for messages to send to all active connection. <code>somekindofstorage</code> could be a map or a vector.

Edit:

Alternatively, you could just store all connections in a global map and write to each from <code>EchoServer</code>. But maps aren't designed to be accessed concurrently.

huangapple
  • 本文由 发表于 2010年8月25日 21:27:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/3566288.html
匿名

发表评论

匿名网友

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

确定