5.5 KiB
8.2 WebSocket
WebSocket is an important feature of HTML5, it implemented remote socket based on browsers, which allows browsers have full-duplex communication with servers. Main stream browsers like Firefox, Google Chrome and Safari have supported this feature.
People often use "roll poling" for instant message services before WebSocket was born, which let clients send HTTP requests in every certain period, then server returns latest data to clients. This requires clients to keep sending a lot of requests and take up a large number of bandwidth.
WebSocket uses a kind of special header to reduce handshake action between browsers and servers to only once, and create a connection. This connection will remain active, you can use JavaScript to write or read data from this the connection, as in the use of a conventional TCP socket. It solves the problem of web real-time development, and has following advantages over traditional HTTP:
- Only one TCP connection for a singe web client.
- WebSocket servers can push data to web clients.
- More lightweight header to reduce data transmission.
WebSocket URL starts with ws:// or wss://(SSL). The following picture shows the communication process of WebSocket, where a particular HTTP header was sent to server for handshake, then servers or clients are able to send or receive data through JavaScript according to some kind of socket, this socket can be used by the event handler to receive data asynchronously.
Figure 8.2 WebSocket principle.
WebSocket principle
WebSocket protocol is quite simple, after the adoption of the first handshake, the connection is established successfully. Subsequent communication data are all begin with "\x00" and ends with "\xFF". Clients will not see these two parts because WebSocket will break off both ends and gives raw data automatically.
WebSocket connection are requested by browsers and responded by servers, then the connection is established, this process is often called "handshake".
Consider the following requests and feedback:
Figure 8.3 WebSocket request and response.
"Sec-WebSocket-key" is generated randomly, as you may guess, this is encoded by base64. Servers need to append this key to a fixed string after accepted:
258EAFA5-E914-47DA-95CA-C5AB0DC85B11
Suppose we have f7cb4ezEAl6C3wRaU6JORA==, then we have:
f7cb4ezEAl6C3wRaU6JORA==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
Use sha1 to compute binary value and use base64 to encode it, then we have:
rE91AJhfC+6JdVcVXOGJEADEJdQ=
Use this as value of Sec-WebSocket-Accept for respond header.
WebSocket in Go
Go standard library does not support WebSocket, but package websocket, which is the sub-package of go.net and maintained by official support it.
Use go get to install this package:
go get code.google.com/p/go.net/websocket
WebSocket has client and server sides, let's see a simple example: user input information, client sends content to server through WebSocket; server pushes information back up 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, JavaScript is very easy to write in client side, and use corresponding function establish a connection. Event onopen triggered after handshake to tell client that connection was created successfully. Client bindings four events:
- 1)onopen: triggered after connection was established.
- 2)onmessage: triggered after received message.
- 3)onerror: triggered after error occurred.
- 4)onclose: triggered after connection 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 client Send user input information, server Receive it, and use Send to return feedback.
Figure 8.4 WebSocket server received information.
Through the example above we see that the client and server side implementation of WebSocket are very convenient. We can use package net directly in Go. Now with rapid develop of HTML5, I think WebSocket will be much more important in web development, we need to reserve this knowledge.


