forked from mirror/websocket
Improve chat example
- Discuss concurrency and message coalescing in the README. - Add comments to client.go explaining how concurrency requirements are met. - Prevent developers from calling the Client.write method from outside of the writePump goroutine by removing the method. The code is now inlined in Client.writPump.
This commit is contained in:
parent
0b847f2fac
commit
6257d10a8b
|
@ -72,6 +72,17 @@ there's an error writing to the websocket connection.
|
||||||
Finally, the HTTP handler calls the client's `readPump` method. This method
|
Finally, the HTTP handler calls the client's `readPump` method. This method
|
||||||
transfers inbound messages from the websocket to the hub.
|
transfers inbound messages from the websocket to the hub.
|
||||||
|
|
||||||
|
WebSocket connections [support one concurrent reader and one concurrent
|
||||||
|
writer](https://godoc.org/github.com/gorilla/websocket#hdr-Concurrency). The
|
||||||
|
application ensures that these concurrency requirements are met by executing
|
||||||
|
all reads from the `readPump` goroutine and all writes from the `writePump`
|
||||||
|
goroutine.
|
||||||
|
|
||||||
|
To improve efficiency under high load, the `writePump` function coalesces
|
||||||
|
pending chat messages in the `send` channel to a single WebSocket message. This
|
||||||
|
reduces the number of system calls and the amount of data sent over the
|
||||||
|
network.
|
||||||
|
|
||||||
## Frontend
|
## Frontend
|
||||||
|
|
||||||
The frontend code is in [home.html](https://github.com/gorilla/websocket/blob/master/examples/chat/home.html).
|
The frontend code is in [home.html](https://github.com/gorilla/websocket/blob/master/examples/chat/home.html).
|
||||||
|
|
|
@ -49,6 +49,10 @@ type Client struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// readPump pumps messages from the websocket connection to the hub.
|
// readPump pumps messages from the websocket connection to the hub.
|
||||||
|
//
|
||||||
|
// The application runs readPump in a per-connection goroutine. The application
|
||||||
|
// ensures that there is at most one reader on a connection by executing all
|
||||||
|
// reads from this goroutine.
|
||||||
func (c *Client) readPump() {
|
func (c *Client) readPump() {
|
||||||
defer func() {
|
defer func() {
|
||||||
c.hub.unregister <- c
|
c.hub.unregister <- c
|
||||||
|
@ -70,13 +74,11 @@ func (c *Client) readPump() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// write writes a message with the given message type and payload.
|
|
||||||
func (c *Client) write(mt int, payload []byte) error {
|
|
||||||
c.conn.SetWriteDeadline(time.Now().Add(writeWait))
|
|
||||||
return c.conn.WriteMessage(mt, payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
// writePump pumps messages from the hub to the websocket connection.
|
// writePump pumps messages from the hub to the websocket connection.
|
||||||
|
//
|
||||||
|
// A goroutine running writePump is started for each connection. The
|
||||||
|
// application ensures that there is at most one writer to a connection by
|
||||||
|
// executing all writes from this goroutine.
|
||||||
func (c *Client) writePump() {
|
func (c *Client) writePump() {
|
||||||
ticker := time.NewTicker(pingPeriod)
|
ticker := time.NewTicker(pingPeriod)
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -86,13 +88,13 @@ func (c *Client) writePump() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case message, ok := <-c.send:
|
case message, ok := <-c.send:
|
||||||
|
c.conn.SetWriteDeadline(time.Now().Add(writeWait))
|
||||||
if !ok {
|
if !ok {
|
||||||
// The hub closed the channel.
|
// The hub closed the channel.
|
||||||
c.write(websocket.CloseMessage, []byte{})
|
c.conn.WriteMessage(websocket.CloseMessage, []byte{})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.conn.SetWriteDeadline(time.Now().Add(writeWait))
|
|
||||||
w, err := c.conn.NextWriter(websocket.TextMessage)
|
w, err := c.conn.NextWriter(websocket.TextMessage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -110,7 +112,8 @@ func (c *Client) writePump() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
if err := c.write(websocket.PingMessage, []byte{}); err != nil {
|
c.conn.SetWriteDeadline(time.Now().Add(writeWait))
|
||||||
|
if err := c.conn.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue