概述
go语言websocket库Gorilla Websocket
文章目录
- go语言websocket库Gorilla Websocket
- 概览
- 数据类消息
- 控制类消息
- 并发
- Origin控制
- 缓冲
概览
Conn
类型代表一个Websocket连接,服务端通过在HTTP请求的handler中调用Upgrader.Upgrade
方法得到一个*Conn
:
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func handler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
... Use conn to send and receive messages.
}
通过调用Conn
的WriteMessage
和ReadMessage
方法来发收消息,消息以byte切片存储。下面例子展示了如何用这两个方法实现echo:
for {
messageType, p, err := conn.ReadMessage()
if err != nil {
log.Println(err)
return
}
if err := conn.WriteMessage(messageType, p); err != nil {
log.Println(err)
return
}
}
上例中:p是[]byte类型。messageType是int型,值可能是websocket.BinaryMessage
或websocket.TextMessage
。
应用程序也可以使用io.WriteCloser
和io.Reader
接口来发收消息。要想发送消息,先调用Conn
的NextWriter
方法得到一个io.WriteCloser
,然后写消息到这个writer,写完消息后close它。要想接收消息,先调用Conn
的NextReader
方法得到一个io.Reader
,然后读直到返回io.EOF
。下面的例子展示如何使用NextWriter
和NextReader
方法实现echo:
for {
messageType, r, err := conn.NextReader()
if err != nil {
return
}
w, err := conn.NextWriter(messageType)
if err != nil {
return err
}
if _, err := io.Copy(w, r); err != nil {
return err
}
if err := w.Close(); err != nil {
return err
}
}
数据类消息
WebSocket协议区分文本消息和二进制消息。文本消息必须是UTF-8编码。
本包使用TextMessage
和BinaryMessage
整型常量来标识这两种消息类型。ReadMessage
和NextReader
方法返回正接收的消息类型。WriteMessage
和NextWriter
方法的messageTyp
参数指定要发送的消息类型。
控制类消息
Websocket协议定义了三种控制消息:Close、Ping和Pong。通过调用Conn
的WriteControl
、WriteMessage
或NextWriter
方法向对端发送控制消息。
Conn
收到了Close消息之后,调用由SetCloseHandler
方法设置的handler函数,然后从NextReader
、ReadMessage
或消息的Read
方法返回一个*CloseError
。缺省的close handler会发送一个Close消息到对端。
Conn
收到了Ping消息之后,调用由SetPingHandler
方法设置的handler函数。缺省的ping handler会发送一个Pong消息到对象。
Conn
收到了Pong消息之后,调用由SetPongHandler
设置的handler函数。缺省的pong handler什么也不做。
控制消息的handler函数是从NextReader
、ReadMessage
和消息的Read
方法中调用的。缺省的close handler和ping handler向对端写数据时可能会短暂阻塞这些方法。
应用程序必须读取Conn
,使得对端发送的close、ping、和pong消息能够得到处理。即使应用程序不关心对端发送的消息,也应该启动一个goroutine来读取对端的消息并丢弃。例如:
func readLoop(c *websocket.Conn) {
for {
if _, _, err := c.NextReader(); err != nil {
c.Close()
break
}
}
}
并发
Conn
支持一个并发的读取和一个并发的写入。
应用程序应该保证不会有多于一个goroutine并发调用写方法(NextWriter
,SetWriteDeadline
,WriteMessage
,WriteJSON
,EnableWriteCompression
,SetCompressionLevel
),而且不会有多于一个goroutine并发调用读方法(NextReader
,SetReadDeadline
,ReadMessage
,ReadJSON
,SetPongHandler
,SetPingHandler
)。
Close
和WriteControl
方法可以被并发的调用。
Origin控制
浏览器允许Javascript应用程序打开连接到任意主机的Websocket。需要由服务端负责根据浏览器请求中的Origin头部来执行一个origin策略。
Upgrader
调用CheckOrigin
域所指定的函数来检查origin。如果CheckOrigin
函数返回false,Upgrade
方法将会握手失败并响应HTTP403状态。
如果CheckOrigin
字段是nil,Upgrarder
将使用一个缺省的安全的策略:当请求头部出现了Origin但值不等于Host头,将会握手失败。
有一个包级别的Upgrade
函数,该函数已经废弃了,该函数不会执行origin检查,应用程序需要在调用该函数之前检查Origin头部。
缓冲
Conn
对网络读写进行缓冲,减少读写消息时的系统调用次数。
写缓冲也用于构建WebSocket帧。每当一个写缓冲被flush到网络时,都会写一个WebSocket帧头到网络。减少写缓冲的尺寸会增加连接上写出的帧数。
通过Dialer
和Upgrader
对象的ReadBufferSize
和WriteBufferSize
域来设置缓冲区的尺寸,以字节为单位。当Dialer
的缓冲区尺寸被设置为0时,将使用缺省的4096。当Upgrader
的缓冲区尺寸被设置为0时,将会重用HTTP server创建的缓冲区。在编写这篇文档的时候,HTTP server的缓冲区尺寸为4096。
缓冲区的尺寸并不会对连接上可读写的消息的大小起到限制。
缺省情况下,在一个连接的整个生命周期中都会持有该缓冲区。但是,如果设置了Dialer
或Upgrader
的WriteBufferPool
域,一个连接的写缓冲区仅仅在写消息的时候被持有。
应用程序可通过调整缓冲区大小来平衡内存使用和性能。增加缓冲区尺寸会导致使用更多的内存,但是可以减少读写网络时的系统调用次数。对于写消息,增加缓冲区尺寸可以减少写出的帧数。
一些设置缓冲区尺寸的方针:
限制缓冲区尺寸小于预期的最大消息大小。缓冲区大于最大消息不会带来什么益处。
基于消息大小的分布情况来设置。设置缓冲区尺寸小于预期的最大消息大小可以大幅的降低内存使用,且对性能仅仅有小幅影响。下面是一个例子:如果99%的消息小于256字节,最大消息大小是512字节,那么设置缓冲区为256字节时的系统调用次数是512字节时的1.01倍,但是内存却节省了50%。
当一个应用程序在大量的连接上执行数量不多的写出时,使用缓冲池将更好。当使用缓冲池时,设置大尺寸的缓冲区也不会带来大量的内存占用,同时还能减少系统调用次数和写出的帧数量。
最后
以上就是畅快野狼为你收集整理的go语言websocket库Gorilla Websocket的全部内容,希望文章能够帮你解决go语言websocket库Gorilla Websocket所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复