如何在Go语言中使用Websockets:最佳工具与行动指南( 二 )


如何在Go语言中使用Websockets:最佳工具与行动指南

文章插图
图:UDP Socket
其他TCP函数都具有UDP对应的函数;只需在上述函数中将TCP替换为UDP 。
客户端:
// init raddr, err := net.ResolveUDPAddr("udp", address) if err != nil { // handle error } conn, err := net.DialUDP("udp", nil, raddr) if err != nil { // handle error } ....... // send message buffer := make([]byte, maxBufferSize) n, addr, err := conn.ReadFrom(buffer) if err != nil { // handle error } .......// receive message buffer := make([]byte, maxBufferSize) n, err = conn.WriteTo(buffer[:n], addr) if err != nil { // handle error }服务端:
// init udpAddr, err := net.ResolveUDPAddr(resolver, serverAddr) if err != nil { // handle error } conn, err := net.ListenUDP("udp", udpAddr) if err != nil { // handle error } ....... // send message buffer := make([]byte, maxBufferSize) n, addr, err := conn.ReadFromUDP(buffer) if err != nil { // handle error } ....... // receive message buffer := make([]byte, maxBufferSize) n, err = conn.WriteToUDP(buffer[:n], addr) if err != nil { // handle error }什么是WebSocket
WebSocket通信协议通过单个TCP连接提供全双工通信通道 。与HTTP相比,WebSocket不需要您发送请求即可获得响应 。它们允许双向数据流,因此您只需等待服务器响应即可 。可用时,它将向您发送一条消息 。
对于需要连续数据交换的服务(例如即时通讯程序,在线游戏和实时交易系统),WebSockets是一个很好的解决方案 。您可以在RFC 6455规范中找到有关WebSocket协议的完整信息 。
WebSocket连接由浏览器请求发起,并由服务器响应,之后连接就建立起来了 。此过程通常称为握手 。WebSockets中的特殊标头仅需要浏览器与服务器之间的一次握手即可建立连接,该连接将在其整个生命周期内保持活动状态 。
WebSockets解决了许多实时Web开发的难题,与传统的HTTP相比,它具有许多优点:
  • 轻量级报头减少了数据传输开销 。
  • 单个Web客户端仅需要一个TCP连接 。
  • WebSocket服务器可以将数据推送到Web客户端 。

如何在Go语言中使用Websockets:最佳工具与行动指南

文章插图
 
图:WebSocket
WebSocket协议实现起来相对简单 。它使用HTTP协议进行初始握手 。成功握手后,连接就建立起来了,并且WebSocket实质上使用原始TCP(raw tcp)来读取/写入数据 。
客户端请求如下所示:
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 Origin: http://example.com这是服务器响应:
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat【如何在Go语言中使用Websockets:最佳工具与行动指南】如何在Go中创建WebSocket应用
要基于该net/http 库编写简单的WebSocket echo服务器,您需要:
  • 发起握手
  • 从客户端接收数据帧
  • 发送数据帧给客户端
  • 关闭握手
首先,让我们创建一个带有WebSocket端点的HTTP处理程序:
// HTTP server with WebSocket endpointfunc Server() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { ws, err := NewHandler(w, r) if err != nil { // handle error } if err = ws.Handshake(); err != nil { // handle error } …然后初始化WebSocket结构 。
初始握手请求始终来自客户端 。服务器确定了WebSocket请求后,需要使用握手响应进行回复 。
请记住,您无法使用http.ResponseWriter编写响应,因为一旦开始发送响应,它将关闭基础TCP连接 。
因此,您需要使用HTTP劫持(hijack) 。通过劫持,您可以接管基础的TCP连接处理程序和bufio.Writer 。这使您可以在不关闭TCP连接的情况下读取和写入数据 。
// NewHandler initializes a new handlerfunc NewHandler(w http.ResponseWriter, req *http.Request) (*WS, error) { hj, ok := w.(http.Hijacker) if !ok { // handle error } .....}要完成握手,服务器必须使用适当的头进行响应 。
// Handshake creates a handshake header func (ws *WS) Handshake() error { hash := func(key string) string { h := sha1.New() h.Write([]byte(key)) h.Write([]byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")) return base64.StdEncoding.EncodeToString(h.Sum(nil)) }(ws.header.Get("Sec-WebSocket-Key")) .....}“Sec-WebSocket-key”是随机生成的,并且是Base64编码的 。接受请求后,服务器需要将此密钥附加到固定字符串 。假设您有x3JJHMbDL1EzLkh9GBhXDw== 钥匙 。在这个例子中,可以使用SHA-1计算二进制值,并使用Base64对其进行编码 。假设你得到HSmrc0sMlYUkAGmm5OPpG2HaGWk= 。使,用它作为Sec-WebSocket-Accept 响应头的值 。


推荐阅读