Files
build-web-application-with-…/8.2.md
2012-10-09 17:02:28 +08:00

148 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#8.2 WebSocket
首先我们了解一下什么是WebSocketWebSocket是HTML5的重要特性其通信协议实现的是基于浏览器的远程socket实现了浏览器和服务器全双工通信许多浏览器Firefox、Google Chrome和Safari都已对此做了支持。
在WebSocket之前为了实现即时通信所用的技术都是轮询在特定的时间间隔内由浏览器对服务器发出HTTP Request然后服务器返回最新的数据给客户端的浏览器但是这样浏览器需要对服务器不断发出请求会占用很多带宽。
WebSocket使得浏览器和服务器只需要要做一个握手的动作其用到了一些特殊的报头。然后浏览器和服务器之间就形成了一条快速通道。连接会保持在活动状态你可以使用JavaScript来写入和接收数据就像是在使用一个原始的TCP Socket一样。两者之间就直接可以数据互相传送它解决了Web实时化的问题相比传统HTTP有如下好处
- 一个Web客户端只建立一个TCP连接
- Websocket服务端可以推送(push)数据到web客户端.
- 有更加轻量级的头,减少数据传送量
WebSocket URL的起始输入是ws://或是wss://在SSL上。下图展示了WebSocket的通信过程一个带有特定报头的HTTP握手被发送到了服务器端接着在服务器端或是客户端就可以通过JavaScript来使用某种套接口socket这一套接口可被用来通过事件句柄异步地接收数据。
![](images/8.2.websocket.png?raw=true)
##WebSocket原理
WebSocket的协议颇为简单在第一次handshake通过以后便建立连接其后的通讯数据都是以”\x00″开头以”\xFF”结尾。在客户端这个是透明的WebSocket组件会自动将原始数据“掐头去尾”。
在实现WebSocket连线过程中需要透过浏览器发出WebSocket连线请求然后服务器发出回应这个过程通常称为“握手” (handshaking)。请看下面的请求和反馈信息:
![](images/8.2.websocket2.png?raw=true)
在请求中的"Sec-WebSocket-Key"是随机的对于整天跟编码打交到的程序员一眼就可以看出来这个是一个经过base64编码后的数据。服务器端接收到这个请求之后需要把这个字符串连接上一个固定的字符串
258EAFA5-E914-47DA-95CA-C5AB0DC85B11
把Sec-WebSocket-Key:后的字符串f7cb4ezEAl6C3wRaU6JORA== 连接上那一串固定字符串,生成一个这样的字符串:
f7cb4ezEAl6C3wRaU6JORA==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
对该字符串先用 sha1安全散列算法计算出二进制的值然后用base64对其进行编码即可以得到握手后的字符串
rE91AJhfC+6JdVcVXOGJEADEJdQ=
生成后输出Sec-WebSocket-Accept响应头反馈给客户端。
##Go实现WebSocket
Go语言标准包里面没有针对WebSocket的支持但是在他的net额外库中有这个的支持首先你可以通过如下的命令获取该代码包
go get code.google.com/p/go.net/websocket
WebSocket分为客户端和服务端我们接下来实现一个简单的例子用户输入信息客户端通过WebSocket发送给服务器端服务器端收到信息之后主动的Push信息到客户端输出相应的信息客户端的代码如下
<html>
<head></head>
<body>
<script type="text/javascript">
var sock = null;
var wsuri = "ws://127.0.0.1:1234";
window.onload = function() {
console.log("onload");
sock = new WebSocket(wsuri);
sock.onopen = function() {
console.log("connected to " + wsuri);
}
sock.onclose = function(e) {
console.log("connection closed (" + e.code + ")");
}
sock.onmessage = function(e) {
console.log("message received: " + e.data);
}
};
function send() {
var msg = document.getElementById('message').value;
sock.send(msg);
};
</script>
<h1>WebSocket Echo Test</h1>
<form>
<p>
Message: <input id="message" type="text" value="Hello, world!">
</p>
</form>
<button onclick="send();">Send Message</button>
</body>
</html>
我们可以看到客户端JS很容易就通过`WebSocket`函数建立了一个sock当客户端握手成功后会触发WebScoket对象的onopen事件告诉客户端连接已经成功建立。客户端一共绑定了四个事件。
- 1onopen 建立连接后触发
- 2onmessage 收到消息后触发
- 3onerror 发生错误时触发
- 4onclose 关闭连接时触发
我们服务器端的实现如下:
package main
import (
"code.google.com/p/go.net/websocket"
"fmt"
"log"
"net/http"
)
func Echo(ws *websocket.Conn) {
var err error
for {
var reply string
if err = websocket.Message.Receive(ws, &reply); err != nil {
fmt.Println("Can't receive")
break
}
fmt.Println("Received back from client: " + reply)
msg := "Received: " + reply
fmt.Println("Sending to client: " + msg)
if err = websocket.Message.Send(ws, msg); err != nil {
fmt.Println("Can't send")
break
}
}
}
func main() {
http.Handle("/", websocket.Handler(Echo))
if err := http.ListenAndServe(":1234", nil); err != nil {
log.Fatal("ListenAndServe:", err)
}
}
当我们再客户端输入信息之后在服务器端通过Receive接收数据然后通过Send发送数据。
![](images/8.2.websocket3.png?raw=true)
通过上面的例子我们看到客户端和服务器端实现WebSocket非常的方便Go的源码net分支中已经实现了这个的协议我们可以直接拿来用目前随着HTML5的发展我想未来WebSocket会是Web开发的一个重点我们需要储备这方面的知识。
## links
* [目录](<preface.md>)
* 上一节: [Socket编程](<8.1.md>)
* 下一节: [REST](<8.3.md>)
## LastModified
* $Id$