golang之websocket 源碼分析


下載go的websocket包. 

1. 通過google官方的方法, 需要hg來同步代碼. 由於牆的原因, 還需要設置代理. 比較麻煩

2. http://gopm.io/ 通過該網站下載, 這是golang中國提供的解決方法 http://www.golangtc.com/download/package

 

websocket的實現還是比較簡單的. 一共就4個文件. client.go  hybi.go server.go websocket.go

示例代碼網上到處都是, 就不貼了. 

有一篇自己實現了一遍websocket的協議的文章 http://www.cnblogs.com/yjf512/archive/2013/02/18/2915171.html

對於理解協議還是比較好的. 當然這個代碼僅限學習. 

 

通過源碼來確定兩件事: 

1. websocket 在接收時會自動組合一個完整的frame拋上來. 即send和recv是一一對應的. 

2. 發送json數據為什么是空的(后來發現和websocket沒啥關系0.0)

 

第一點. 是我很少用web框架. 孤陋寡聞了. 后來問了一下java的同事, 現在的框架基本都做了自動拆解包. 

golang的websocket支持兩種codec. Message和json形式. 

Message 就是直接發送字符流. 

json 即在內部自動調用json的解析器. 

c++中發送一般都控制得很精准. json會浪費很多冗余數據. 雖然比起xml來說更輕量. 但是擴展性和通用性的好處是顯而易見的. 

 

這部分代碼在websocket.go中. 

var JSON = Codec{jsonMarshal, jsonUnmarshal}
var Message = Codec{marshal, unmarshal}

receive的處理如下:

// Receive receives single frame from ws, unmarshaled by cd.Unmarshal and stores in v.
func (cd Codec) Receive(ws *Conn, v interface{}) (err error) {
    .... // 省略
again:
    frame, err := ws.frameReaderFactory.NewFrameReader()
    if err != nil {
        return err
    }
    frame, err = ws.frameHandler.HandleFrame(frame)
    if err != nil {
        return err
    }
    if frame == nil {
        goto again
    }
    payloadType := frame.PayloadType()
    data, err := ioutil.ReadAll(frame)
    if err != nil {
        return err
    }
    return cd.Unmarshal(data, payloadType, v)
}

frame的處理代碼在hybi.go中. 

// NewFrameReader reads a frame header from the connection, and creates new reader for the frame.
// See Section 5.2 Base Framing protocol for detail.
// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5.2
func (buf hybiFrameReaderFactory) NewFrameReader() (frame frameReader, err error) {
    hybiFrame := new(hybiFrameReader)
    // ... 解析websocket的協議頭.
    hybiFrame.reader = io.LimitReader(buf.Reader, hybiFrame.header.Length)
    hybiFrame.header.data = bytes.NewBuffer(header)
    hybiFrame.length = len(header) + int(hybiFrame.header.Length)
    return
}

在此處根據header.length 接受完整個frame的數據. 

而HandleFrame中主要是判斷frame的payloadtype. 

 

第二點. 這個是golang的struct 的坑了. 

對於小寫的成員. 其他包是無法訪問的. 所以json的Marshal和Unmarshal 為空. 然而又不會報錯或者異常. 害我糾結了半天. 

解決方法有兩個: 

1. 成員變量首字母大寫. 

2. 實現json.Marshaler接口 

對於第二種, 可以參考這篇文章. http://blog.csdn.net/varding/article/details/38560681

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM