-
最終的效果如下
Web端上傳的信息
Web端得到的打印的信息
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)的伪冰。極光官方文檔
- Timer
WebSocket URL的起始輸入是
ws://
或是wss://
(在SSL上)誓酒。一個帶有特定報頭的HTTP握手被發(fā)送到了服務器端,接著在服務器端或是客戶端就可以通過JavaScript來使用某種套接口(socket)贮聂,這一套接口可被用來通過事件句柄異步地接收數(shù)據(jù)靠柑。
WebSocket 原理
- WebSocket的協(xié)議:在第一次
handshake
通過以后,連接便建立成功吓懈,其后的通訊數(shù)據(jù)都是以”\x00″開頭歼冰,以”\xFF”結尾。在客戶端耻警,這個是透明的隔嫡,WebSocket
組件會自動將原始數(shù)據(jù)“掐頭去尾”甸怕。
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=
,如下圖所示
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
包剪切進去就可以