GO语言实现websocket握手

7个月前 0 0 123

Go

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实现

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。

版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)

评论 (0)

    暂无评论~

njphper@copyright From 2014 to 2019-02-17