From a6a9613a3f48925ab311419349765b9883afd2d2 Mon Sep 17 00:00:00 2001 From: astaxie Date: Tue, 9 Oct 2012 17:02:28 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BA=86WebSocket=E7=9A=84?= =?UTF-8?q?=E7=BC=96=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 8.1.md | 2 +- 8.2.md | 142 +++++++++++++++++++++++++++++++++++++- 8.3.md | 2 +- 8.md | 2 +- images/8.2.websocket.png | Bin 0 -> 8446 bytes images/8.2.websocket2.png | Bin 0 -> 14880 bytes images/8.2.websocket3.png | Bin 0 -> 2036 bytes preface.md | 2 +- 8 files changed, 145 insertions(+), 5 deletions(-) create mode 100644 images/8.2.websocket.png create mode 100644 images/8.2.websocket2.png create mode 100644 images/8.2.websocket3.png diff --git a/8.1.md b/8.1.md index a3f38c6e..64b207f7 100644 --- a/8.1.md +++ b/8.1.md @@ -285,7 +285,7 @@ Go语言包中处理UDP Socket和TCP Socket不同的地方就是在处理服务 ## links * [目录]() * 上一节: [Web服务](<8.md>) - * 下一节: [webSockets](<8.2.md>) + * 下一节: [WebSocket](<8.2.md>) ## LastModified * $Id$ \ No newline at end of file diff --git a/8.2.md b/8.2.md index 5f4f86ca..ca4492e8 100644 --- a/8.2.md +++ b/8.2.md @@ -1,4 +1,144 @@ -#8.2 webSockets +#8.2 WebSocket +首先我们了解一下什么是WebSocket?WebSocket是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信息到客户端,输出相应的信息,客户端的代码如下: + + + + + +

WebSocket Echo Test

+
+

+ Message: +

+
+ + + + + +我们可以看到客户端JS很容易就通过`WebSocket`函数建立了一个sock,当客户端握手成功后,会触发WebScoket对象的onopen事件,告诉客户端连接已经成功建立。客户端一共绑定了四个事件。 + +- 1)onopen 建立连接后触发 +- 2)onmessage 收到消息后触发 +- 3)onerror 发生错误时触发 +- 4)onclose 关闭连接时触发 + +我们服务器端的实现如下: + + 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 * [目录]() * 上一节: [Socket编程](<8.1.md>) diff --git a/8.3.md b/8.3.md index 94000f82..b1a132a8 100644 --- a/8.3.md +++ b/8.3.md @@ -1,7 +1,7 @@ #8.3 REST ## links * [目录]() - * 上一节: [webSockets](<8.2.md>) + * 上一节: [WebSocket](<8.2.md>) * 下一节: [RPC](<8.4.md>) ## LastModified diff --git a/8.md b/8.md index 3d4a50db..fc9408b5 100644 --- a/8.md +++ b/8.md @@ -13,7 +13,7 @@ Go语言是21世纪的C语言,我们追求的是性能、简单,所以我们 ## 目录 * 1. [Socket编程](8.1.md) - * 2. [webSockets](8.2.md) + * 2. [WebSocket](8.2.md) * 3. [REST](8.3.md) * 4. [RPC](8.4.md) * 5. [小结](8.5.md) diff --git a/images/8.2.websocket.png b/images/8.2.websocket.png new file mode 100644 index 0000000000000000000000000000000000000000..64d63e73224f67195ac02169804bc24d66584c95 GIT binary patch literal 8446 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 P92|yvCb~qVebj#e-1Tb& literal 0 HcmV?d00001 diff --git a/images/8.2.websocket2.png b/images/8.2.websocket2.png new file mode 100644 index 0000000000000000000000000000000000000000..b744c634e265331e1130aeea15ced4f884aefdb7 GIT binary patch literal 14880 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 literal 0 HcmV?d00001 diff --git a/preface.md b/preface.md index 46f23590..828d0286 100644 --- a/preface.md +++ b/preface.md @@ -48,7 +48,7 @@ - 7.5 [小结](7.5.md) * 8.[Web服务](8.md) - 8.1 [Socket编程](8.1.md) - - 8.2 [webSockets](8.2.md) + - 8.2 [WebSocket](8.2.md) - 8.3 [REST](8.3.md) - 8.4 [RPC](8.4.md) - 8.5 [小结](8.5.md)