GO语言实现websocket握手

Websocket

websocket作为h5新的API, 基于HTTP的新协议, 具体资料请自行搜索

Websocket标准头信息

GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: 127.0.0.1:8000
Origin: http://127.0.0.1:8000
Sec-WebSocket-Key: hj0eNqbhE/A0GkBXDRrYYw==
Sec-WebSocket-Version: 13

Sec-WebSocket-Key是由客户端(浏览器)发起的, 主要就是要根据这个来进行握手

Websocket标准response

HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept:secret

握手的关键就在这个响应的Sec-WebSocket-Accept,服务要通过Sec-WebSocket-Key和常量字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11合并成新的字符串之后进行sha1加密, 然后在进行base64加密之后得到Sec-WebSocket-Accept, 返回给客户端认证握手。

GO实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package main

import (
"net"
"fmt"
"strings"
"crypto/sha1"
"io"
"encoding/base64"
)

const (
WEBSOCKET_KEY = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
)

func main() {
connect()
}


func connect() {
//监听
ln, err := net.Listen("tcp", ":8000")
if err != nil {
fmt.Println(err)
}

for {
//接受客户端连接
conn, err := ln.Accept()
if err != nil {
fmt.Println(err)
}

for {
handConnect(conn)
}
}
}

func handConnect(conn net.Conn) {
content := make([]byte, 1024)
n, err := conn.Read(content)
if err != nil {
fmt.Println(err)
}
fmt.Println(fmt.Sprintf("读取%d个字节", n))

header := parseHeaders(string(content))
fmt.Println(header["Sec-WebSocket-Key"])

secret := getSecret(header["Sec-WebSocket-Key"])

response := "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
response += "Upgrade: websocket\r\n"
response +="Connection: Upgrade\r\n"
response +="Sec-WebSocket-Accept: " + secret +"\r\n"
response += "\r\n"

conn.Write([]byte(response))

}

func parseHeaders(content string) map[string]string {
h := strings.Split(content, "\r\n")
header := make(map[string]string, 0)
for _, value := range h {
v := strings.Split(value, ":")
//注意这里切片长度一定要大于2
if len(v) >= 2 {
//空格也必须去除
header[strings.Trim(v[0], " ")] = strings.Trim(v[1], " ")
}
}
return header
}

func getSecret(key string) string{
key += WEBSOCKET_KEY
res := sha1.New()
io.WriteString(res, key)
return base64.StdEncoding.EncodeToString(res.Sum(nil))
}

上面就是简单的实现, 然后就是如何解析frame。