英文:
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 <- 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 { //assuming the client disconnected on write errors
somekindofstorage.Remove(v)
}
}
}
}
}()
http.Handle("/echo", websocket.Handler(EchoServer));
http.ListenAndServe(":12345", 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论