1. 程式人生 > >淺析websocket與websocket連線數測試

淺析websocket與websocket連線數測試


       WebSocket是html5新增加的一種通訊協議,我們知道HTTP協議是一種單向的網路協議,在建立連線後,它只允許瀏覽器客戶端向WebServer發出請求資源後,WebServer才能返回相應的資料。即WebServer不能主動的推送資料,但是面對在web系統上實時聊天的這類需求,基於HTTP協議實現會很麻煩,公司專案組開發的線上客服系統中也有這樣的需求,為了更好地實現,採用的是websocket技術。而測試系統的websocket的效能也是我的工作之一。

一、websocket簡介
       WebSocket協議是一種雙向通訊協議,它建立在TCP之上,同http一樣通過TCP來傳輸資料,都是可靠的連線,但是它和http最大的不同有兩點:
       1.WebSocket是一種雙向通訊協議,在建立連線後,WebSocket伺服器和Browser/UA都能主動的向對方傳送或接收資料,就像Socket一樣,不同的是WebSocket是一種建立在Web基礎上的一種簡單模擬Socket的協議;
       2.WebSocket需要通過握手連線,類似於TCP它也需要客戶端和伺服器端進行握手連線,連線成功後才能相互通訊。
  
       那麼建立一個websocket連線,是一個怎麼樣的握手過程呢,(總共4次哦)首先進行TCP的連線,三次握手成功後再進行一次websocket的握手:
       Browser/UA通過http協議傳送WebSocket支援的版本號,協議的字版本號,原始地址,主機地址等等一些列欄位給伺服器端;
       WebSocket伺服器收到Browser/UA傳送來的握手請求後,如果資料包資料和格式正確,客戶端和伺服器端的協議版本號匹配等等,就接受本次握手連線,並給出相應的資料採用http協議傳輸回覆,
        Browser收到伺服器回覆的資料包後,如果資料包內容、格式都沒有問題的話,就表示本次連線成功,觸發onopen訊息,此時Web開發者就可以在此時通過send介面想伺服器傳送資料。否則,握手連線失敗。
        另外,搭建websocket的伺服器比較困難,可以利用一些開源庫,直接呼叫其中解析和封裝websocket資料的介面,會輕鬆很多。

二、websocket效能測試

    對於基於websocket協議的線上聊天的系統來說,得保證其穩定性,連線數作為效能指標,測試websocket的併發連線數非常重要,另外還有連線能力,就是模擬測試websocket併發地傳送訊息。而用一般的web測試工具無法測,需要編寫測試指令碼進行自動化測試(有大神協助。。。)
    測試websocket的連線數就是同時開啟多個執行緒,呼叫websocket的API進行連線建立,測出最大連線數(併發連線數),並用日誌記錄連線情況。
      在建立websocket連線時,首先獲取登陸認證的唯一ticket(類似登陸使用者的ID),cookies,HTTP協議版本以及伺服器地址、websocket介面等,加到websocket的請求報文中,發起連線,接收到接受伺服器的響應ACK內容,則連線成功。
      下面是部分go語言實現的主要程式碼
<span style="font-size:18px;"> func main() {
    var wg sync.WaitGroup
    var index = 0
    // var temp = 0
    for _, empCode := range EmpCodes {//依次開啟每個賬號的執行緒
        index = index + 1
        if index > 1 {
        break
    }
    log.Printf("index:%v", index)
    wg.Add(1)</span>
<span style="font-size:18px;">
    go func(code string) {
       defer wg.Done()
       err := SimulateKeepOnline(code)//呼叫建立websocket連線的方法
       if err != nil {
           log.Printf("[%s] has error: %s", code, err.Error())
           return
       }
    }(empCode)
  }

  wg.Wait()//併發啟動執行緒

}

func SimulateKeepOnline(empCode string) error {
    log.Printf("[%s] Begin...", empCode)
    defer log.Printf("[%s] Exit...", empCode)
    ticket, err := ConnectorAuth(empCode)
    if err != nil {
      return err
    }
    // Extract the cookie for later use
    log.Printf("[%s] Establishing websocket connection...", empCode)

    // Establish websocket connection
    var wsHeader = http.Header(make(map[string][]string))
    cookie := http.Cookie{
        Name:  "WS_TICKET",
        Value: ticket,
    }
    wsHeader.Add("Cookie", cookie.String())
    //伺服器地址
    wsConfig, err := NewConfig("ws://ws.xxx.cn/employee/ws", "http://ws.xxx.cn")
    if err != nil {
        return err
    }
    wsConfig.Header = wsHeader
    wsConn, err := DialConfig(wsConfig)
    if err != nil {
        return err
    }
    log.Printf("[%s] IsClientConn: %v", empCode, wsConn.IsClientConn())
    log.Printf("[%s] IsServerConn: %v", empCode, wsConn.IsServerConn())
    log.Printf("[%s] LocalAddr: %+v", empCode, wsConn.LocalAddr())
    log.Printf("[%s] RemoteAddr: %+v", empCode, wsConn.RemoteAddr())
    log.Printf("[%s] Receiving upstream messages...", empCode)
    for {
        var message string
        //接受伺服器傳送的響應ACK
        if err := Message.Receive(wsConn, &message); err != nil {
            return err
            continue
        }
        log.Printf("[%s] received: %s", empCode, message)
    }
}
</span>

      而測試連線能力是用程式碼模擬在websocket併發地傳送訊息,在建立websocket連線之後,可以開始向伺服器傳送訊息,通過日誌記錄檢測併發地傳送訊息時系統是否報錯。