Go实战--Gorilla web toolkit使用之gorilla/websocket

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wangshubo1989/article/details/79140278

这里写图片描述
声明不止,继续 go go go!!!

关于websocket,不会陌生。
之前也有博客介绍过golang中使用websocket,其中介绍了两个第三方库:
gorilla/websocket
nkovacs/go-socket.io

Go实战–golang中使用WebSocket实时聊天室(gorilla/websocket、nkovacs/go-socket.io)

所以,趁着介绍gorilla工具博客系列,今天就再重新介绍一下gorilla/websocket。

WebSocket

WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。 WebSocket通信协议于2011年被IETF定为标准RFC 6455,WebSocketAPI被W3C定为标准。 在WebSocket API中,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

TCP: low-level, bi-directional, full-duplex, and guaranteed order transport layer. No browser support (except via plugin/Flash).

HTTP 1.0: request-response transport protocol layered on TCP. The client makes one full request, the server gives one full response, and then the connection is closed. The request methods (GET, POST, HEAD) have specific transactional meaning for resources on the server.

HTTP 1.1: maintains the request-response nature of HTTP 1.0, but allows the connection to stay open for multiple full requests/full responses (one response per request). Still has full headers in the request and response but the connection is re-used and not closed. HTTP 1.1 also added some additional request methods (OPTIONS, PUT, DELETE, TRACE, CONNECT) which also have specific transactional meanings. However, as noted in the introduction to the HTTP 2.0 draft proposal, HTTP 1.1 pipelining is not widely deployed so this greatly limits the utility of HTTP 1.1 to solve latency between browsers and servers.

Long-poll: sort of a “hack” to HTTP (either 1.0 or 1.1) where the server does not response immediately (or only responds partially with headers) to the client request. After a server response, the client immediately sends a new request (using the same connection if over HTTP 1.1).

HTTP streaming: a variety of techniques (multipart/chunked response) that allow the server to send more than one response to a single client request. The W3C is standardizing this as Server-Sent Events using a text/event-stream MIME type. The browser API (which is fairly similar to the WebSocket API) is called the EventSource API.
Comet/server push: this is an umbrella term that includes both long-poll and HTTP streaming. Comet libraries usually support multiple techniques to try and maximize cross-browser and cross-server support.

WebSockets: a transport layer built-on TCP that uses an HTTP friendly Upgrade handshake. Unlike TCP, which is a streaming transport, WebSockets is a message based transport: messages are delimited on the wire and are re-assembled in-full before delivery to the application. WebSocket connections are bi-directional, full-duplex and long-lived. After the initial handshake request/response, there is no transactional semantics and there is very little per message overhead. The client and server may send messages at any time and must handle message receipt asynchronously.

HTTP 2.0: has similar goals to SPDY: reduce HTTP latency and overhead while preserving HTTP semantics. The current draft is derived from SPDY and defines an upgrade handshake and data framing that is very similar the the WebSocket standard for handshake and framing. An alternate HTTP 2.0 draft proposal (httpbis-speed-mobility) actually uses WebSockets for the transport layer and adds the SPDY multiplexing and HTTP mapping as an WebSocket extension (WebSocket extensions are negotiated during the handshake).

WebRTC/CU-WebRTC: proposals to allow peer-to-peer connectivity between browsers. This may enable lower average and maximum latency communication because as the underlying transport is SDP/datagram rather than TCP. This allows out-of-order delivery of packets/messages which avoids the TCP issue of latency spikes caused by dropped packets which delay delivery of all subsequent packets (to guarantee in-order delivery).

特点:
(1)建立在 TCP 协议之上,服务器端的实现比较容易。

(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

(3)数据格式比较轻量,性能开销小,通信高效。

(4)可以发送文本,也可以发送二进制数据。

(5)没有同源限制,客户端可以与任意服务器通信。

(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL

gorilla/websocket

获取:
go get github.com/gorilla/websocket

API:
这里写图片描述

官方例子:
https://github.com/gorilla/websocket/tree/master/examples/chat

HTML5 WebSocket

以下 API 用于创建 WebSocket 对象。

var Socket = new WebSocket(url, [protocol] );

事件
open Socket.onopen 连接建立时触发
message Socket.onmessage 客户端接收服务端数据时触发
error Socket.onerror 通信发生错误时触发
close Socket.onclose 连接关闭时触发

例子:

<!DOCTYPE HTML>
<html>
   <head>
   <meta charset="utf-8">
   <title>菜鸟教程(runoob.com)</title>

      <script type="text/javascript">
         function WebSocketTest()
         {
            if ("WebSocket" in window)
            {
               alert("您的浏览器支持 WebSocket!");

               // 打开一个 web socket
               var ws = new WebSocket("ws://localhost:9998/echo");

               ws.onopen = function()
               {
                  // Web Socket 已连接上,使用 send() 方法发送数据
                  ws.send("发送数据");
                  alert("数据发送中...");
               };

               ws.onmessage = function (evt) 
               { 
                  var received_msg = evt.data;
                  alert("数据已接收...");
               };

               ws.onclose = function()
               { 
                  // 关闭 websocket
                  alert("连接已关闭..."); 
               };
            }

            else
            {
               // 浏览器不支持 WebSocket
               alert("您的浏览器不支持 WebSocket!");
            }
         }
      </script>

   </head>
   <body>

      <div id="sse">
         <a href="javascript:WebSocketTest()">运行 WebSocket</a>
      </div>

   </body>
</html>

简单例子h5+golang

main.go

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"

    "github.com/gorilla/websocket"
)

type msg struct {
    Num int
}

func main() {
    http.HandleFunc("/ws", wsHandler)
    http.HandleFunc("/", rootHandler)

    panic(http.ListenAndServe(":8080", nil))
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
    content, err := ioutil.ReadFile("index.html")
    if err != nil {
        fmt.Println("Could not open file.", err)
    }
    fmt.Fprintf(w, "%s", content)
}

func wsHandler(w http.ResponseWriter, r *http.Request) {
    if r.Header.Get("Origin") != "http://"+r.Host {
        http.Error(w, "Origin not allowed", 403)
        return
    }
    conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024)
    if err != nil {
        http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
    }

    go echo(conn)
}

func echo(conn *websocket.Conn) {
    for {
        m := msg{}

        err := conn.ReadJSON(&m)
        if err != nil {
            fmt.Println("Error reading json.", err)
        }

        fmt.Printf("Got message: %#v\n", m)

        if err = conn.WriteJSON(m); err != nil {
            fmt.Println(err)
        }
    }
}

index.html

<html>
<head>
    <title>WebSocket demo</title>
</head>
<body>

    <div>
        <form>
            <label for="numberfield">Number</label>
            <input type="text" id="numberfield" placeholder="input"/><br />
            <button type="button" id="sendBtn">Send</button>
        </form>
    </div>
    <div id="container"></div>

    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script type="text/javascript">
        $(function () {
            var ws;

            if (window.WebSocket === undefined) {
                $("#container").append("Your browser does not support WebSockets");
                return;
            } else {
                ws = initWS();
            }

            function initWS() {
                var socket = new WebSocket("ws://localhost:8080/ws"),
                    container = $("#container")
                socket.onopen = function() {
                    container.append("<p>Socket is open</p>");
                };
                socket.onmessage = function (e) {
                    container.append("<p> Got some shit:" + e.data + "</p>");
                }
                socket.onclose = function () {
                    container.append("<p>Socket closed</p>");
                }

                return socket;
            }

            $("#sendBtn").click(function (e) {
                e.preventDefault();
                ws.send(JSON.stringify({ Num: parseInt($("#numberfield").val()) }));
            });
        });
    </script>
</body>
</html>

这里写图片描述

猜你喜欢

转载自blog.csdn.net/wangshubo1989/article/details/79140278