Go語言實現(xiàn)的WebSocket

  • 最終的效果如下


    Web端上傳的信息

    Web端得到的打印的信息
服務端的代碼的實現(xiàn)
服務端的信息
  • WebSocket協(xié)議是基于TCP的一種新的網(wǎng)絡協(xié)議敢伸。它實現(xiàn)了瀏覽器與服務器全雙工(full-duplex)通信——允許服務器主動發(fā)送信息給客戶端替劈。WebSocket通信協(xié)議于2011年被IETF定為標準RFC 6455拯杠,并被RFC7936所補充規(guī)范晾嘶。WebSocket是HTML5的重要特性健盒,它實現(xiàn)了基于瀏覽器的遠程socket沾谜,它使瀏覽器和服務器可以進行全雙工通信涛碑,許多瀏覽器Firefox嗜暴、Google Chrome和Safari都已對此做了支持

  • WebSocket出現(xiàn)之前凸克,為了實現(xiàn)即時通信,采用的技術都是“輪詢”闷沥,即在特定的時間間隔內(nèi)萎战,由瀏覽器對服務器發(fā)出HTTP Request,服務器在收到請求后舆逃,返回最新的數(shù)據(jù)給瀏覽器刷新蚂维,“輪詢”使得瀏覽器需要對服務器不斷發(fā)出請求戳粒,這樣會占用大量帶寬。

  • 很多的游戲的服務都是采用的是Socket虫啥,因為HTTP協(xié)議相對而言比較耗費性能蔚约, 隨著HTML5的發(fā)展,WebSocket也逐漸發(fā)展成為很多頁游公司接下來開發(fā)的一些手段涂籽。

  • 安卓推送的原理: C2DM 推送 (Google) C2DM 推送簡介 : 全稱 Cloudto Device Messaging, Google 提供的 推送解決方案;

    • 運行方式 : 提供一個輕量級機制, 允許服務器通知應用程序, 主動與客戶端進行數(shù)據(jù)交互, 處理消息排隊, 并向運行于目標設備的應用程序分發(fā)消息;
    • 優(yōu)點 : Google 提供的原生框架, 無需在應用中添加第三方代碼 和 部署服務器端;
    • 缺點 : 1.該推送依賴 Google 服務器, 需要綁定 Google 帳號, 目前在中國 Google 被屏蔽, 無法使用; 2. 許多手機廠商去掉了軟件中的該模塊;
  • 極光推送的原理:因為IP v4 的 IP 量有限苹祟,運營商分配給手機終端的 IP 是運營商內(nèi)網(wǎng)的 IP,手機要連接 Internet评雌,就需要通過運營商的網(wǎng)關做一個網(wǎng)絡地址轉換Network Address Translation树枫,NAT。簡單的說運營商的網(wǎng)關需要維護一個外網(wǎng) IP景东、端口到內(nèi)網(wǎng) IP砂轻、端口的對應關系,以確保內(nèi)網(wǎng)的手機可以跟 Internet 的服務器通訊斤吐。

  • Android 平臺上長連接的實現(xiàn)

    • Timer
      Android 的 Timer 類可以用來計劃需要循環(huán)執(zhí)行的任務搔涝,Timer 的問題是它需要用 WakeLock 讓 CPU 保持喚醒狀態(tài),這樣會大量消耗手機電量曲初,大大減短手機待機時間体谒。
    • AlarmManager 這篇文章有介紹怎么使用AlarmManager安卓網(wǎng)絡和電量優(yōu)化
      AlarmManager 是 Android 系統(tǒng)封裝的用于管理 RTC 的模塊,RTC (Real Time Clock) 是一個獨立的硬件時鐘臼婆,可以在 CPU 休眠時正常運行,在預設的時間到達時幌绍,通過中斷喚醒 CPU颁褂。
      這意味著,如果我們用 AlarmManager 來定時執(zhí)行任務傀广,CPU 可以正常的休眠颁独,只有在需要運行任務時醒來一段很短的時間。極光推送的 Android SDK 就是基于這種技術實現(xiàn)的伪冰。極光官方文檔
  • WebSocket URL的起始輸入是ws://或是wss://(在SSL上)誓酒。一個帶有特定報頭的HTTP握手被發(fā)送到了服務器端,接著在服務器端或是客戶端就可以通過JavaScript來使用某種套接口(socket)贮聂,這一套接口可被用來通過事件句柄異步地接收數(shù)據(jù)靠柑。

WebSocket 原理

  • WebSocket的協(xié)議:在第一次handshake通過以后,連接便建立成功吓懈,其后的通訊數(shù)據(jù)都是以”\x00″開頭歼冰,以”\xFF”結尾。在客戶端耻警,這個是透明的隔嫡,WebSocket組件會自動將原始數(shù)據(jù)“掐頭去尾”甸怕。
request的信息.png
GET http://localhost:8080/shiming HTTP/1.1
Host: localhost:8080
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: file://
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: zh-CN,zh;q=0.8
Cookie: _ga=GA1.1.27955907.1529919744
Sec-WebSocket-Key: PCD+pA79juC6tlBK9zD3Vw==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

  • Sec-WebSocket-Key這個是個隨機的值,是一個經(jīng)過base64編寫后的數(shù)據(jù)Sec-WebSocket-Key: PCD+pA79juC6tlBK9zD3Vw==
  • 然后服務器收到這個請求之后把這個字符串連接上一個固定的字符串 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 為啥是這樣的腮恩,我目前還不明白梢杭,僅僅是自己記錄下而已。
  • 最終得到:
PCD+pA79juC6tlBK9zD3Vw==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
  • 對該字符使用shal 安全散列算法計算出二進制的值秸滴,然后用base64 對其進行編碼武契,即可以得到握手的字符串: 8+5CLWTBYLARKoxBxS5uk6s6zZo= ,如下圖所示
response信息.png
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 8+5CLWTBYLARKoxBxS5uk6s6zZo=

  • Sec-WebSocket-Accept作為響應頭的值反饋給客戶端。

Go語言實現(xiàn)Websocket

  • 由于Go語言標準包里面沒有對WebSocket的支持缸榛,但是官方維護的go.net對這個有支持吝羞,所以可以獲取
go get golang.org/net/websocket
  • 但是有個小問題,當我 go get后内颗,我在代碼中導入包會報錯钧排,同時去掉x也不行,所以我在本地目錄創(chuàng)建了一個x的目錄均澳,然后把net全部放進去了
    注意問題.png

    導包
  • html 代碼
<html>
<head>
    <title>好好學習</title>
</head>
<body>
<script type="text/javascript">
    var sock = null;
    // var wsuri = "wss://127.0.0.1:8080"; //本地的地址 是可以改變的哦
     var wsuri = "ws://localhost:8080/shiming"; //本地的地址 是可以改變的哦


    window.onload = function() {
        //可以看到客戶端JS恨溜,很容易的就通過WebSocket函數(shù)建立了一個與服務器的連接sock,當握手成功后找前,會觸發(fā)WebScoket對象的onopen事件糟袁,告訴客戶端連接已經(jīng)成功建立√墒ⅲ客戶端一共綁定了四個事件项戴。
        console.log("開始了 onload");

        sock = new WebSocket(wsuri);
        //建立連接后觸發(fā)
        sock.onopen = function() {
            console.log(" 建立連接后觸發(fā) connected to " + wsuri);
        }
        // 關閉連接時候觸發(fā)
        sock.onclose = function(e) {
            console.log("關閉連接時候觸發(fā) connection closed (" + e.code + ")");
        }
        // 收到消息后觸發(fā)
        sock.onmessage = function(e) {
            console.log("收到消息后觸發(fā) message received: " + e.data);
        }
        //發(fā)生錯誤的時候觸發(fā)
        sock.onerror=function (e) {
            console.log("發(fā)生錯誤時候觸發(fā)"+wsuri)
        }
    };
     //如果sock被關閉掉了 這里 也會報錯的啊
    function send() {
        var msg = document.getElementById('message').value;
        sock.send(msg);
    };
</script>
<h1>GoWebSocketDemo</h1>
<form>
    <p>
        Message: <input id="message" type="text" value="你好啊  shiming 小哥哥  嘿嘿   ">
    </p>
</form>
<button onclick="send();">給服務器發(fā)送消息</button>
</body>
</html>
  • go 代碼
package main

import (
    "fmt"
    "net/http"
    //草擬嗎 自己創(chuàng)建的目錄 哈哈哈哈哈    還好我比較聰明  要不然 就完蛋了  麻痹
    "golang.org/x/net/websocket"
    "log"
)

func main() {
    fmt.Println("Go語言標準包里面沒有提供對WebSocket的支持,但是在由官方維護的go.net子包中有對這個的支持 go get golang.org/x/net/websocket")
    //打印這個信息就槽惫,os.Exit(1)  退出程序
    //log.Fatal("shiming")  todo  草擬嗎 啊   看清楚啊   后面的域名的地址 有個老子的名字啊
    http.Handle("/shiming",websocket.Handler(Echo))
     if err:=http.ListenAndServe(":8080",nil);err!=nil{
        log.Fatal(err)
     }


}

func Echo(w *websocket.Conn)  {
    var error error
    for   {
        var reply string
        if  error= websocket.Message.Receive(w,&reply);error!=nil{
            fmt.Println("不能夠接受消息 error==",error)
            break
        }
        fmt.Println("能夠接受到消息了--- ",reply)
        msg:="我已經(jīng)收到消息 Received:"+reply
        //  連接的話 只能是   string周叮;類型的啊
        fmt.Println("發(fā)給客戶端的消息: "+msg)

        if error = websocket.Message.Send(w, msg); error != nil {
            fmt.Println("不能夠發(fā)送消息 悲催哦")
            break
        }
    }
}
  • 說明一點:http.Handle("/shiming",websocket.Handler(funName)),如果在這里有路由的話,記得在 html中也要改成一樣的, html中的代碼 :var wsuri = "ws://localhost:8080/shiming"
  • x目錄自己創(chuàng)建一個界斜,把net包剪切進去就可以
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末仿耽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子各薇,更是在濱河造成了極大的恐慌项贺,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件峭判,死亡現(xiàn)場離奇詭異开缎,居然都是意外死亡,警方通過查閱死者的電腦和手機朝抖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門啥箭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人治宣,你說我怎么就攤上這事急侥∑鲋停” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵坏怪,是天一觀的道長昔脯。 經(jīng)常有香客問我铛楣,道長护戳,這世上最難降的妖魔是什么看成? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮鹏秋,結果婚禮上尊蚁,老公的妹妹穿的比我還像新娘。我一直安慰自己侣夷,他們只是感情好横朋,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著百拓,像睡著了一般琴锭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上衙传,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天决帖,我揣著相機與錄音,去河邊找鬼蓖捶。 笑死地回,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的俊鱼。 我是一名探鬼主播落君,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼亭引!你這毒婦竟也來了?” 一聲冷哼從身側響起皮获,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤焙蚓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后洒宝,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體购公,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年雁歌,在試婚紗的時候發(fā)現(xiàn)自己被綠了宏浩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡靠瞎,死狀恐怖比庄,靈堂內(nèi)的尸體忽然破棺而出求妹,到底是詐尸還是另有隱情,我是刑警寧澤佳窑,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布制恍,位于F島的核電站,受9級特大地震影響神凑,放射性物質(zhì)發(fā)生泄漏净神。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一溉委、第九天 我趴在偏房一處隱蔽的房頂上張望鹃唯。 院中可真熱鬧,春花似錦瓣喊、人聲如沸坡慌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽八匠。三九已至,卻和暖如春趴酣,著一層夾襖步出監(jiān)牢的瞬間梨树,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工岖寞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留抡四,地道東北人。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓仗谆,卻偏偏與公主長得像指巡,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子隶垮,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容