我创建了一个发布JSON流的简单websocket。我在大多数情况下工作正常,除了我认为在循环通过客户端发送消息时的几种情况,它会挂在异常断开的客户端上。我可以在此代码中添加哪些措施来缓解它?
Client.go
import (
"github.com/gorilla/websocket"
)
type client struct {
socket *websocket.Conn
send chan *Message
}
func (c *client) read() {
defer c.socket.Close()
for {
_, _, err := c.socket.ReadMessage()
if err != nil {
log.Info("Websocket: %s", err)
break
}
}
}
func (c *client) write() {
defer c.socket.Close()
for msg := range c.send {
err := c.socket.WriteJSON(msg)
if err != nil {
break
}
}
}
Stream.go
import (
"net/http"
"github.com/gorilla/websocket"
)
const (
socketBufferSize = 1024
messageBufferSize = 256
)
var upgrader = &websocket.Upgrader{
ReadBufferSize: socketBufferSize,
WriteBufferSize: socketBufferSize,
}
type Stream struct {
Send chan *Message
join chan *client
leave chan *client
clients map[*client]bool
}
func (s *Stream) Run() {
for {
select {
case client := <-s.join: // joining
s.clients[client] = true
case client := <-s.leave: // leaving
delete(s.clients, client)
close(client.send)
case msg := <-s.Send: // send message to all clients
for client := range s.clients {
client.send <- msg
}
}
}
}
func (s *Stream) ServeHTTP(w http.ResponseWriter, res *http.Request) {
socket, err := upgrader.Upgrade(w, res, nil)
if err != nil {
log.Error(err)
return
}
defer func() {
socket.Close()
}()
client := &client{
socket: socket,
send: make(chan *Message, messageBufferSize),
}
s.join <- client
defer func() { s.leave <- client }()
go client.write()
client.read()
}
答案 0 :(得分:2)
有关如何避免在客户端上阻止的示例,请参阅Gorilla Chat Application。
关键部分是:
Use a buffered channel for sending to the client。您的申请已经在执行此操作。
Send to the client using select/default以避免阻止。当客户端无法立即收到消息时,假设客户端在写入时被阻止。在这种情况下关闭客户端的通道,导致客户端的写循环退出。