Documentation ¶
Index ¶
- Constants
- Variables
- func GenUkFlvPullSession() string
- func GenUkFlvSubSession() string
- func GenUkGroup() string
- func GenUkHlsMuxer() string
- func GenUkRtmpPullSession() string
- func GenUkRtmpPushSession() string
- func GenUkRtmpServerSession() string
- func GenUkRtspPubSession() string
- func GenUkRtspPullSession() string
- func GenUkRtspPushSession() string
- func GenUkRtspServerCommandSession() string
- func GenUkRtspSubSession() string
- func GenUkStreamer() string
- func GenUkTsSubSession() string
- func IsUseClosedConnectionError(err error) bool
- func MakeWsFrameHeader(wsHeader WsHeader) (buf []byte)
- func OsExitAndWaitPressIfWindows(code int)
- func UpdateWebSocketHeader(secWebSocketKey string) []byte
- type ApiCtrlKickOutSession
- type ApiCtrlStartPullReq
- type ApiStatAllGroup
- type ApiStatGroup
- type ApiStatLalInfo
- type AvPacket
- type AvPacketPt
- type Handler
- type HttpResponseBasic
- type HttpServerManager
- type HttpSubSession
- func (session *HttpSubSession) AppName() string
- func (session *HttpSubSession) Dispose() error
- func (session *HttpSubSession) GetStat() StatSession
- func (session *HttpSubSession) IsAlive() (readAlive, writeAlive bool)
- func (session *HttpSubSession) RawQuery() string
- func (session *HttpSubSession) RunLoop() error
- func (session *HttpSubSession) StreamName() string
- func (session *HttpSubSession) UniqueKey() string
- func (session *HttpSubSession) UpdateStat(intervalSec uint32)
- func (session *HttpSubSession) Url() string
- func (session *HttpSubSession) Write(b []byte)
- func (session *HttpSubSession) WriteHttpResponseHeader(b []byte)
- type HttpSubSessionOption
- type IBufWriter
- type IClientSession
- type IClientSessionLifecycle
- type IObject
- type IServerSession
- type IServerSessionLifecycle
- type ISessionStat
- type ISessionUrlContext
- type LalInfo
- type LocalAddrCtx
- type PubStartInfo
- type PubStopInfo
- type RtmpConnectInfo
- type RtmpHeader
- type RtmpMsg
- func (msg RtmpMsg) Clone() (ret RtmpMsg)
- func (msg RtmpMsg) IsAacSeqHeader() bool
- func (msg RtmpMsg) IsAvcKeyNalu() bool
- func (msg RtmpMsg) IsAvcKeySeqHeader() bool
- func (msg RtmpMsg) IsHevcKeyNalu() bool
- func (msg RtmpMsg) IsHevcKeySeqHeader() bool
- func (msg RtmpMsg) IsVideoKeyNalu() bool
- func (msg RtmpMsg) IsVideoKeySeqHeader() bool
- type ServerCtx
- type SessionEventCommonInfo
- type StatGroup
- type StatPub
- type StatPull
- type StatSession
- type StatSub
- type SubStartInfo
- type SubStopInfo
- type UpdateInfo
- type UrlContext
- func ParseHttpUrl(rawUrl string, isHttps bool, suffix string) (ctx UrlContext, err error)
- func ParseHttpflvUrl(rawUrl string, isHttps bool) (ctx UrlContext, err error)
- func ParseHttptsUrl(rawUrl string, isHttps bool) (ctx UrlContext, err error)
- func ParseRtmpUrl(rawUrl string) (ctx UrlContext, err error)
- func ParseRtspUrl(rawUrl string) (ctx UrlContext, err error)
- func ParseUrl(rawUrl string, defaultPort int) (ctx UrlContext, err error)
- type UrlPathContext
- type WriterFunc
- type WsHeader
- type WsOpcode
Constants ¶
const ( ErrorCodeSucc = 0 DespSucc = "succ" ErrorCodeGroupNotFound = 1001 DespGroupNotFound = "group not found" ErrorCodeParamMissing = 1002 DespParamMissing = "param missing" ErrorCodeSessionNotFound = 1003 DespSessionNotFound = "session not found" )
const ( // spec-rtmp_specification_1.0.pdf // 7.1. Types of Messages RtmpTypeIdAudio uint8 = 8 RtmpTypeIdVideo uint8 = 9 RtmpTypeIdMetadata uint8 = 18 // RtmpTypeIdDataMessageAmf0 RtmpTypeIdSetChunkSize uint8 = 1 RtmpTypeIdAck uint8 = 3 RtmpTypeIdUserControl uint8 = 4 RtmpTypeIdWinAckSize uint8 = 5 RtmpTypeIdBandwidth uint8 = 6 RtmpTypeIdCommandMessageAmf3 uint8 = 17 RtmpTypeIdCommandMessageAmf0 uint8 = 20 RtmpTypeIdAggregateMessage uint8 = 22 // user control message type RtmpUserControlStreamBegin uint8 = 0 RtmpUserControlRecorded uint8 = 4 // spec-video_file_format_spec_v10.pdf // Video tags // VIDEODATA // FrameType UB[4] // CodecId UB[4] // AVCVIDEOPACKET // AVCPacketType UI8 // CompositionTime SI24 // Data UI8[n] RtmpFrameTypeKey uint8 = 1 RtmpFrameTypeInter uint8 = 2 RtmpCodecIdAvc uint8 = 7 RtmpCodecIdHevc uint8 = 12 RtmpAvcPacketTypeSeqHeader uint8 = 0 RtmpAvcPacketTypeNalu uint8 = 1 RtmpHevcPacketTypeSeqHeader = RtmpAvcPacketTypeSeqHeader RtmpHevcPacketTypeNalu = RtmpAvcPacketTypeNalu RtmpAvcKeyFrame = RtmpFrameTypeKey<<4 | RtmpCodecIdAvc RtmpHevcKeyFrame = RtmpFrameTypeKey<<4 | RtmpCodecIdHevc RtmpAvcInterFrame = RtmpFrameTypeInter<<4 | RtmpCodecIdAvc RtmpHevcInterFrame = RtmpFrameTypeInter<<4 | RtmpCodecIdHevc // spec-video_file_format_spec_v10.pdf // Audio tags // AUDIODATA // SoundFormat UB[4] // SoundRate UB[2] // SoundSize UB[1] // SoundType UB[1] // AACAUDIODATA // AACPacketType UI8 // Data UI8[n] RtmpSoundFormatAac uint8 = 10 // 注意,视频的CodecId是后4位,音频是前4位 RtmpAacPacketTypeSeqHeader = 0 RtmpAacPacketTypeRaw = 1 )
const ( // 注意,一般情况下,AVC使用96,AAC使用97,HEVC使用98 // 但是我还遇到过: // HEVC使用96 // AVC使用105 RtpPacketTypeAvcOrHevc = 96 RtpPacketTypeAac = 97 RtpPacketTypeHevc = 98 )
const ( // StatGroup.AudioCodec AudioCodecAac = "AAC" // StatGroup.VideoCodec VideoCodecAvc = "H264" VideoCodecHevc = "H265" // StatSession.Protocol ProtocolRtmp = "RTMP" ProtocolRtsp = "RTSP" ProtocolHttpflv = "HTTP-FLV" ProtocolHttpts = "HTTP-TS" )
const ( UkPreRtmpServerSession = "RTMPPUBSUB" UkPreRtmpPushSession = "RTMPPUSH" UkPreRtmpPullSession = "RTMPPULL" UkPreRtspServerCommandSession = "RTSPSRVCMD" UkPreRtspPubSession = "RTSPPUB" UkPreRtspSubSession = "RTSPSUB" UkPreRtspPushSession = "RTSPPUSH" UkPreRtspPullSession = "RTSPPULL" UkPreFlvSubSession = "FLVSUB" UkPreTsSubSession = "TSSUB" UkPreFlvPullSession = "FLVPULL" UkPreGroup = "GROUP" UkPreHlsMuxer = "HLSMUXER" UkPreStreamer = "STREAMER" )
const ( DefaultRtmpPort = 1935 DefaultHttpPort = 80 DefaultHttpsPort = 443 DefaultRtspPort = 554 )
const HttpApiVersion = "v0.1.4"
const HttpNotifyVersion = "v0.1.0"
const LalVersion = "v0.24.0"
版本,该变量由外部脚本修改维护
const (
NetworkTcp = "tcp"
)
const WsMagicStr = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
Variables ¶
var ( ErrAddrEmpty = errors.New("lal.base: http server addr empty") ErrMultiRegistForPattern = errors.New("lal.base: http server multiple registrations for pattern") )
var ( LalLibraryName = "lal" LalGithubRepo = "github.com/cfeeling/lal" LalGithubSite = "https://github.com/cfeeling/lal" LalDocSite = "https://pengrl.com/lal" // e.g. lal v0.12.3 (github.com/cfeeling/lal) LalFullInfo = LalLibraryName + " " + LalVersion + " (" + LalGithubRepo + ")" // e.g. 0.12.3 LalVersionDot string // e.g. 0,12,3 LalVersionComma string )
var ( // 植入rtmp握手随机字符串中 // e.g. lal v0.12.3 (github.com/cfeeling/lal) LalRtmpHandshakeWaterMark string // 植入rtmp server中的connect result信令中 // 注意,有两个object,第一个object中的fmsVer我们保持通用公认的值,在第二个object中植入 // e.g. 0,12,3 LalRtmpConnectResultVersion string // e.g. lal0.12.3 LalRtmpPushSessionConnectVersion string // e.g. lal0.12.3 LalRtmpBuildMetadataEncoder string // e.g. lal/0.12.3 LalHttpflvPullSessionUa string // e.g. lal0.12.3 LalHttpflvSubSessionServer string // e.g. lal0.12.3 LalHlsM3u8Server string // e.g. lal0.12.3 LalHlsTsServer string // e.g. lal0.12.3 LalRtspOptionsResponseServer string // e.g. lal0.12.3 LalHttptsSubSessionServer string // e.g. lal0.12.3 LalHttpApiServer string // e.g. lal/0.12.3 LalRtspPullSessionUa string // e.g. lal 0.12.3 LalPackSdp string )
var (
ErrSessionNotStarted = errors.New("lal.base: session has not been started yet")
)
var ErrUrl = errors.New("lal.url: fxxk")
var (
Logger = nazalog.GetGlobalLogger()
)
Functions ¶
func GenUkFlvPullSession ¶ added in v0.24.1
func GenUkFlvPullSession() string
func GenUkFlvSubSession ¶ added in v0.24.1
func GenUkFlvSubSession() string
func GenUkGroup ¶ added in v0.24.1
func GenUkGroup() string
func GenUkHlsMuxer ¶ added in v0.24.1
func GenUkHlsMuxer() string
func GenUkRtmpPullSession ¶ added in v0.24.1
func GenUkRtmpPullSession() string
func GenUkRtmpPushSession ¶ added in v0.24.1
func GenUkRtmpPushSession() string
func GenUkRtmpServerSession ¶ added in v0.24.1
func GenUkRtmpServerSession() string
func GenUkRtspPubSession ¶ added in v0.24.1
func GenUkRtspPubSession() string
func GenUkRtspPullSession ¶ added in v0.24.1
func GenUkRtspPullSession() string
func GenUkRtspPushSession ¶ added in v0.24.1
func GenUkRtspPushSession() string
func GenUkRtspServerCommandSession ¶ added in v0.24.1
func GenUkRtspServerCommandSession() string
func GenUkRtspSubSession ¶ added in v0.24.1
func GenUkRtspSubSession() string
func GenUkStreamer ¶ added in v0.24.1
func GenUkStreamer() string
func GenUkTsSubSession ¶ added in v0.24.1
func GenUkTsSubSession() string
func IsUseClosedConnectionError ¶ added in v0.24.1
IsUseClosedConnectionError 当connection处于这些情况时,就不需要再Close了 TODO(chef): 临时放这 TODO(chef): 目前暂时没有使用,因为connection支持多次调用Close
func MakeWsFrameHeader ¶ added in v0.24.1
func OsExitAndWaitPressIfWindows ¶ added in v0.24.1
func OsExitAndWaitPressIfWindows(code int)
func UpdateWebSocketHeader ¶ added in v0.19.12
Types ¶
type ApiCtrlKickOutSession ¶ added in v0.24.1
type ApiCtrlStartPullReq ¶ added in v0.24.1
type ApiStatAllGroup ¶ added in v0.24.1
type ApiStatAllGroup struct { HttpResponseBasic Data struct { Groups []StatGroup `json:"groups"` } `json:"data"` }
type ApiStatGroup ¶ added in v0.24.1
type ApiStatGroup struct { HttpResponseBasic Data *StatGroup `json:"data"` }
type ApiStatLalInfo ¶ added in v0.24.1
type ApiStatLalInfo struct { HttpResponseBasic Data LalInfo `json:"data"` }
type AvPacket ¶ added in v0.24.1
type AvPacket struct { Timestamp uint32 PayloadType AvPacketPt Payload []byte }
不同场景使用时,字段含义可能不同。 使用AvPacket的地方,应注明各字段的含义。
type AvPacketPt ¶ added in v0.24.1
type AvPacketPt int
const ( AvPacketPtUnknown AvPacketPt = -1 AvPacketPtAvc AvPacketPt = RtpPacketTypeAvcOrHevc AvPacketPtHevc AvPacketPt = RtpPacketTypeHevc AvPacketPtAac AvPacketPt = RtpPacketTypeAac )
func (AvPacketPt) ReadableString ¶ added in v0.24.1
func (a AvPacketPt) ReadableString() string
type HttpResponseBasic ¶ added in v0.24.1
type HttpServerManager ¶ added in v0.24.1
type HttpServerManager struct {
// contains filtered or unexported fields
}
func NewHttpServerManager ¶ added in v0.24.1
func NewHttpServerManager() *HttpServerManager
func (*HttpServerManager) AddListen ¶ added in v0.24.1
func (s *HttpServerManager) AddListen(addrCtx LocalAddrCtx, pattern string, handler Handler) error
@param pattern 必须以`/`开始,并以`/`结束
func (*HttpServerManager) Dispose ¶ added in v0.24.1
func (s *HttpServerManager) Dispose() error
func (*HttpServerManager) RunLoop ¶ added in v0.24.1
func (s *HttpServerManager) RunLoop() error
type HttpSubSession ¶ added in v0.24.1
type HttpSubSession struct { HttpSubSessionOption // contains filtered or unexported fields }
func NewHttpSubSession ¶ added in v0.24.1
func NewHttpSubSession(option HttpSubSessionOption) *HttpSubSession
func (*HttpSubSession) AppName ¶ added in v0.24.1
func (session *HttpSubSession) AppName() string
func (*HttpSubSession) Dispose ¶ added in v0.24.1
func (session *HttpSubSession) Dispose() error
func (*HttpSubSession) GetStat ¶ added in v0.24.1
func (session *HttpSubSession) GetStat() StatSession
func (*HttpSubSession) IsAlive ¶ added in v0.24.1
func (session *HttpSubSession) IsAlive() (readAlive, writeAlive bool)
func (*HttpSubSession) RawQuery ¶ added in v0.24.1
func (session *HttpSubSession) RawQuery() string
func (*HttpSubSession) RunLoop ¶ added in v0.24.1
func (session *HttpSubSession) RunLoop() error
func (*HttpSubSession) StreamName ¶ added in v0.24.1
func (session *HttpSubSession) StreamName() string
func (*HttpSubSession) UniqueKey ¶ added in v0.24.1
func (session *HttpSubSession) UniqueKey() string
func (*HttpSubSession) UpdateStat ¶ added in v0.24.1
func (session *HttpSubSession) UpdateStat(intervalSec uint32)
func (*HttpSubSession) Url ¶ added in v0.24.1
func (session *HttpSubSession) Url() string
func (*HttpSubSession) Write ¶ added in v0.24.1
func (session *HttpSubSession) Write(b []byte)
func (*HttpSubSession) WriteHttpResponseHeader ¶ added in v0.24.1
func (session *HttpSubSession) WriteHttpResponseHeader(b []byte)
type HttpSubSessionOption ¶ added in v0.24.1
type HttpSubSessionOption struct { Conn net.Conn ConnModOption connection.ModOption Uk string // unique key Protocol string UrlCtx UrlContext IsWebSocket bool WebSocketKey string }
type IBufWriter ¶ added in v0.24.1
type IBufWriter interface { Write(p []byte) Flush() }
func NewWriterFuncSize ¶ added in v0.24.1
func NewWriterFuncSize(wr WriterFunc, size int) IBufWriter
type IClientSession ¶ added in v0.19.12
type IClientSession interface { IClientSessionLifecycle ISessionUrlContext IObject ISessionStat }
type IClientSessionLifecycle ¶ added in v0.19.12
type IClientSessionLifecycle interface { // Dispose 主动关闭session时调用 // // 注意,只有Start(具体session的Start类型函数一般命令为Push和Pull)成功后的session才能调用,否则行为未定义 // // Dispose可在任意协程内调用 // // 注意,目前Dispose允许调用多次,但是未来可能不对该表现做保证 // // Dispose后,调用Write函数将返回错误 // // @return 可以通过返回值判断调用Dispose前,session是否已经被关闭了 TODO(chef) 这个返回值没有太大意义,后面可能会删掉 // Dispose() error // WaitChan Start成功后,可使用这个channel来接收session结束的消息 // // 注意,只有Start成功后的session才能调用,否则行为未定义 // // 注意,目前WaitChan只会被通知一次,但是未来可能不对该表现做保证,业务方应该只关注第一次通知 // // TODO(chef): 是否应该严格保证:获取到关闭消息后,后续不应该再有该session的回调上来 // // @return 一般关闭有以下几种情况: // - 对端关闭,此时error为EOF // - 本端底层关闭,比如协议非法等,此时error为具体的错误值 // - 本端上层主动调用Dispose关闭,此时error为nil // WaitChan() <-chan error }
type IServerSession ¶ added in v0.19.12
type IServerSession interface { IServerSessionLifecycle ISessionUrlContext IObject ISessionStat }
type IServerSessionLifecycle ¶ added in v0.19.12
type ISessionStat ¶
type ISessionStat interface { // 周期性调用该函数,用于计算bitrate // // intervalSec 距离上次调用的时间间隔,单位毫秒 UpdateStat(intervalSec uint32) // 获取session状态 // // @return 注意,结构体中的`Bitrate`的值由最近一次`func UpdateStat`调用计算决定,其他值为当前最新值 GetStat() StatSession // 周期性调用该函数,判断是否有读取、写入数据 // 注意,判断的依据是,距离上次调用该函数的时间间隔内,是否有读取、写入数据 // 注意,不活跃,并一定是链路或网络有问题,也可能是业务层没有写入数据 // // @return readAlive 读取是否获取 // @return writeAlive 写入是否活跃 IsAlive() (readAlive, writeAlive bool) }
调用约束:对于Client类型的Session,调用Start函数并返回成功后才能调用,否则行为未定义
type ISessionUrlContext ¶ added in v0.24.1
type ISessionUrlContext interface { Url() string AppName() string StreamName() string RawQuery() string }
获取和流地址相关的信息
调用约束:对于Client类型的Session,调用Start函数并返回成功后才能调用,否则行为未定义
type LocalAddrCtx ¶ added in v0.24.1
type PubStartInfo ¶
type PubStartInfo struct {
SessionEventCommonInfo
}
type PubStopInfo ¶
type PubStopInfo struct {
SessionEventCommonInfo
}
type RtmpConnectInfo ¶ added in v0.24.1
type RtmpHeader ¶ added in v0.24.1
type RtmpMsg ¶ added in v0.24.1
type RtmpMsg struct { Header RtmpHeader Payload []byte // Payload不包含Header内容。如果需要将RtmpMsg序列化成RTMP chunk,可调用rtmp.ChunkDivider相关的函数 }
func (RtmpMsg) IsAacSeqHeader ¶ added in v0.24.1
func (RtmpMsg) IsAvcKeyNalu ¶ added in v0.24.1
func (RtmpMsg) IsAvcKeySeqHeader ¶ added in v0.24.1
func (RtmpMsg) IsHevcKeyNalu ¶ added in v0.24.1
func (RtmpMsg) IsHevcKeySeqHeader ¶ added in v0.24.1
func (RtmpMsg) IsVideoKeyNalu ¶ added in v0.24.1
func (RtmpMsg) IsVideoKeySeqHeader ¶ added in v0.24.1
type ServerCtx ¶ added in v0.24.1
type ServerCtx struct {
// contains filtered or unexported fields
}
type SessionEventCommonInfo ¶
type SessionEventCommonInfo struct { Protocol string `json:"protocol"` SessionId string `json:"session_id"` RemoteAddr string `json:"remote_addr"` ServerId string `json:"server_id"` Url string `json:"url"` AppName string `json:"app_name"` StreamName string `json:"stream_name"` UrlParam string `json:"url_param"` HasInSession bool `json:"has_in_session"` HasOutSession bool `json:"has_out_session"` }
type StatGroup ¶
type StatGroup struct { StreamName string `json:"stream_name"` AudioCodec string `json:"audio_codec"` VideoCodec string `json:"video_codec"` VideoWidth int `json:"video_width"` VideoHeight int `json:"video_height"` StatPub StatPub `json:"pub"` StatSubs []StatSub `json:"subs"` StatPull StatPull `json:"pull"` }
type StatPub ¶
type StatPub struct {
StatSession
}
func StatSession2Pub ¶
func StatSession2Pub(ss StatSession) (ret StatPub)
type StatPull ¶
type StatPull struct {
StatSession
}
func StatSession2Pull ¶
func StatSession2Pull(ss StatSession) (ret StatPull)
type StatSession ¶
type StatSession struct { Protocol string `json:"protocol"` SessionId string `json:"session_id"` RemoteAddr string `json:"remote_addr"` StartTime string `json:"start_time"` ReadBytesSum uint64 `json:"read_bytes_sum"` WroteBytesSum uint64 `json:"wrote_bytes_sum"` Bitrate int `json:"bitrate"` ReadBitrate int `json:"read_bitrate"` WriteBitrate int `json:"write_bitrate"` }
type StatSub ¶
type StatSub struct {
StatSession
}
func StatSession2Sub ¶
func StatSession2Sub(ss StatSession) (ret StatSub)
type SubStartInfo ¶
type SubStartInfo struct {
SessionEventCommonInfo
}
type SubStopInfo ¶
type SubStopInfo struct {
SessionEventCommonInfo
}
type UpdateInfo ¶
type UrlContext ¶ added in v0.24.1
type UrlContext struct { Url string Scheme string Username string Password string StdHost string // host or host:port HostWithPort string Host string Port int //UrlPathContext PathWithRawQuery string Path string PathWithoutLastItem string // 注意,没有前面的'/',也没有后面的'/' LastItemOfPath string // 注意,没有前面的'/' RawQuery string RawUrlWithoutUserInfo string }
TODO chef: 考虑把rawUrl也放入其中
func ParseHttpUrl ¶ added in v0.24.1
func ParseHttpUrl(rawUrl string, isHttps bool, suffix string) (ctx UrlContext, err error)
func ParseHttpflvUrl ¶ added in v0.24.1
func ParseHttpflvUrl(rawUrl string, isHttps bool) (ctx UrlContext, err error)
func ParseHttptsUrl ¶ added in v0.24.1
func ParseHttptsUrl(rawUrl string, isHttps bool) (ctx UrlContext, err error)
func ParseRtmpUrl ¶ added in v0.24.1
func ParseRtmpUrl(rawUrl string) (ctx UrlContext, err error)
func ParseRtspUrl ¶ added in v0.24.1
func ParseRtspUrl(rawUrl string) (ctx UrlContext, err error)
type UrlPathContext ¶ added in v0.24.1
type WriterFunc ¶ added in v0.24.1
type WriterFunc func(p []byte)
type WsOpcode ¶ added in v0.19.12
type WsOpcode = uint8
The WebSocket Protocol https://tools.ietf.org/html/rfc6455
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-------+-+-------------+-------------------------------+ |F|R|R|R| opcode|M| Payload len | Extended payload length | |I|S|S|S| (4) |A| (7) | (16/64) | |N|V|V|V| |S| | (if payload len==126/127) | | |1|2|3| |K| | | +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + | Extended payload length continued, if payload len == 127 | + - - - - - - - - - - - - - - - +-------------------------------+ | |Masking-key, if MASK set to 1 | +-------------------------------+-------------------------------+ | Masking-key (continued) | Payload Data | +-------------------------------- - - - - - - - - - - - - - - - + : Payload Data continued ... : + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + | Payload Data continued ... | +---------------------------------------------------------------+ opcode: * %x0 denotes a continuation frame * %x1 denotes a text frame * %x2 denotes a binary frame * %x3-7 are reserved for further non-control frames * %x8 denotes a connection close * %x9 denotes a ping * %xA denotes a pong * %xB-F are reserved for further control frames Payload length: 7 bits, 7+16 bits, or 7+64 bits Masking-key: 0 or 4 bytes mark 加密
for i := 0; i < datalen; i { m := markingkeys[i%4] data[i] = msg[i] ^ m }