Merging other languages

This commit is contained in:
James Miranda
2016-09-23 18:01:10 -03:00
parent 380a8ee74c
commit de3c5bdaa4
490 changed files with 24539 additions and 24588 deletions

View File

@@ -1,151 +1,159 @@
# 8.2 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)
图8.2 WebSocket原理图
## WebSocket原理
WebSocket的协议颇为简单在第一次handshake通过以后连接便建立成功其后的通讯数据都是以”\x00″开头以”\xFF”结尾。在客户端这个是透明的WebSocket组件会自动将原始数据“掐头去尾”。
浏览器发出WebSocket连接请求,然后服务器发出回应,然后连接建立成功,这个过程通常称为“握手” (handshaking)。请看下面的请求和反馈信息:
![](images/8.2.websocket2.png?raw=true)
图8.3 WebSocket的requestresponse信息
在请求中的"Sec-WebSocket-Key"是随机的对于整天跟编码打交到的程序员一眼就可以看出来这个是一个经过base64编码后的数据。服务器端接收到这个请求之后需要把这个字符串连接上一个固定的字符串
258EAFA5-E914-47DA-95CA-C5AB0DC85B11
即:`f7cb4ezEAl6C3wRaU6JORA==`连接上那一串固定字符串,生成一个这样的字符串:
f7cb4ezEAl6C3wRaU6JORA==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
对该字符串先用 sha1安全散列算法计算出二进制的值然后用base64对其进行编码即可以得到握手后的字符串
rE91AJhfC+6JdVcVXOGJEADEJdQ=
将之作为响应头`Sec-WebSocket-Accept`的值反馈给客户端。
## Go实现WebSocket
Go语言标准包里面没有提供对WebSocket的支持但是在由官方维护的go.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 (
"golang.org/x/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)
}
}
当客户端将用户输入的信息Send之后服务器端通过Receive接收到了相应信息然后通过Send发送了应答信息。
![](images/8.2.websocket3.png?raw=true)
图8.4 WebSocket服务器端接收到的信息
通过上面的例子我们看到客户端和服务器端实现WebSocket非常的方便Go的源码net分支中已经实现了这个的协议我们可以直接拿来用目前随着HTML5的发展我想未来WebSocket会是Web开发的一个重点我们需要储备这方面的知识。
## links
* [目录](<preface.md>)
* 上一节: [Socket编程](<08.1.md>)
* 下一节: [REST](<08.3.md>)
# 8.2 WebSockets
WebSockets are an important feature of HTML5. It implements browser based remote sockets, which allows browsers to have full-duplex communications with servers. Main stream browsers like Firefox, Google Chrome and Safari provide support for this WebSockets.
People often used "roll polling" for instant messaging services before WebSockets were born, which allow clients to send HTTP requests periodically. The server then returns the latest data to clients. The downside to this method is that it requires clients to keep sending many requests to the server, which can consume a large amount of bandwidth.
WebSockets use a special kind of header that reduces the number of handshakes required between browser and server to only one, for establishing a connection. This connection will remain active throughout its lifetime, and you can use JavaScript to write or read data from this connection, as in the case of a conventional TCP sockets. It solves many of the headache involved with real-time web development, and has the following advantages over traditional HTTP:
- Only one TCP connection for a single web client.
- WebSocket servers can push data to web clients.
- Lightweight header to reduce data transmission overhead.
WebSocket URLs begin with ws:// or wss://(SSL). The following figure shows the communication process of WebSockets. A particular HTTP header is sent to the server as part of the handshaking protocol and the connection is established. Then, servers or clients are able to send or receive data through JavaScript via WebSocket. This socket can then be used by an event handler to receive data asynchronously.
![](images/8.2.websocket.png?raw=true)
Figure 8.2 WebSocket principl
## WebSocket principles
The WebSocket protocol is actually quite simple. After successfully completing the initial handshake, a connection is established. Subsequent data communications will all begin with "\x00" and end with "\xFF". This prefix and suffix will be visible to clients because the WebSocket will break off both end, yielding the raw data automatically.
WebSocket connections are requested by browsers and responded to by servers, after which the connection is established. This process is often called "handshaking".
Consider the following requests and responses:
![](images/8.2.websocket2.png?raw=true)
Figure 8.3 WebSocket request and response.
"Sec-WebSocket-key" is generated randomly, as you may have already guessed, and it's base64 encoded. Servers need to append this key to a fixed string after accepting a request:
258EAFA5-E914-47DA-95CA-C5AB0DC85B11
Suppose we have `f7cb4ezEAl6C3wRaU6JORA==`, then we have:
f7cb4ezEAl6C3wRaU6JORA==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
Use sha1 to compute the binary value and use base64 to encode it. We will then we have:
rE91AJhfC+6JdVcVXOGJEADEJdQ=
Use this as the value of the `Sec-WebSocket-Accept` response header.
## WebSocket in Go
The Go standard library does not support WebSockets. However the `websocket` package, which is a sub-package of `go.net` does, and is officially maintained and supported.
Use `go get` to install this package:
go get code.google.com/p/go.net/websocket
WebSockets have both client and server sides. Let's see a simple example where a user inputs some information on the client side and sends it to the server through a WebSocket, followed by the server pushing information back to the client.
Client code:
<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>
As you can see, it's very easy to use the client side JavaScript functions to establish a connection. The `onopen` event gets triggered after successfully completing the aforementioned handshaking process. It tells the client that the connection has been created successfully. Clients attempting to open a connection typically bind to four events:
- 1onopen: triggered after connection has been established.
- 2onmessage: triggered after receiving a message.
- 3onerror: triggered after an error has occurred..
- 4onclose: triggered after the connection has closed.
Server code:
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)
}
}
When a client `Send`s user input information, the server `Receive`s it, and uses `Send` once again to return a response.
![](images/8.2.websocket3.png?raw=true)
Figure 8.4 WebSocket server received information.
Through the example above, we can see that the client and server side implementation of WebSockets is very convenient. We can use the `net` package directly in Go. With the rapid development of HTML5, I think that WebSockets will take on a much more important role in modern day web development; we should all be at least a little bit familiar with them.
## Links
- [Directory](preface.md)
- Previous section: [Sockets](08.1.md)
- Next section: [REST](08.3.md)