WebSocket based on the Golang

Source: Internet
Author: User
Tags base64 encode unsupported
This is a creation in Article, where the information may have evolved or changed.

The message notification in the project is used by WebSocket, which feels better than HTTP long connection chunking, and is hereby recorded.
The WebSocket protocol is expressed in WS. In addition, there is the WSS protocol, which represents the encrypted WebSocket protocol, which corresponds to the HTTPS protocol.
After the handshake is complete, the WebSocket protocol is on top of the TCP protocol and begins transmitting data

WebSocket principle and operating mechanism

WebSocket is HTML5 under a new protocol. It realizes the browser and the server full-duplex communication, can better save the server resources and bandwidth and achieve the purpose of real-time communication. It transmits data in the same way as HTTP through an established TCP connection, but it differs from the HTTP maximum: WebSocket is a bidirectional communication protocol. After the connection is established, both the WebSocket server and the client can proactively send or receive data to each other, just like a socket, and websocket need to establish a connection like TCP to communicate with each other before the connection succeeds. The traditional HTTP client and server request response modes are as follows:


WebSocket mode client and server request response modes such as:


As can be seen, = = relative to the traditional HTTP each request-response requires the client and the server to establish a connection mode, WebSocket is similar to the socket TCP long connection communication mode. Once the WebSocket connection is established, subsequent data is transmitted in the form of a frame sequence. There is no need for the client and server to re-initiate connection requests before the client disconnects the WebSocket connection or the servers end the connection. In the case of large amount of concurrency and high client-server interaction load, the consumption of network bandwidth resources is greatly saved, and the performance advantage is obvious, and the client sends and receives messages on the same persistent connection, and the real-time advantage is obvious.

Compared to HTTP long connections, WebSocket has the following features:

    • Is the true full duplex approach, after establishing the connection client and server side is completely equal, can be unsolicited requests from each other. HTTP long connections are based on HTTP, which is the traditional mode of client-to-server requests. HTTP long connection, each data exchange in addition to the real data part, the server and the client also have to exchange a large number of HTTP headers, information exchange efficiency is very low.

    • After the WebSocket protocol establishes a TCP connection through the first request, the data exchanged does not need to send an HTTP header to exchange data. This obviously differs from the original HTTP protocol, so it needs to be upgraded to both the server and the client (HTML5 is supported by mainstream browsers).

    • In addition, there are multiplexing, different URLs can be reused the same websocket connection and other functions. These are the HTTP long connections that cannot be done.

    • Regular heartbeat detection after connection is established

On the client, new WebSocket instantiates a WebSocket client object that requests a server-side websocket URL similar to Ws://yourdomain:port/path. The client WebSocket object is automatically parsed and recognized as a websocket request, and connects to the server port, performing both handshake processes, and the client sends a data format similar to:

GET /webfin/websocket/ HTTP/1.1Host: localhostUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==Origin: http://localhost:8080Sec-WebSocket-Version: 13

As you can see, the client-initiated WebSocket connection message is similar to the traditional HTTP message

    • The Upgrade:websocket parameter value indicates that this is a WebSocket type request,

    • Sec-websocket-key is a base64 encoded ciphertext sent by the WebSocket client that requires the server to return a corresponding encrypted sec-websocket-accept answer, or the client throws an error during WebSocket handshake Error and closes the connection.

Upgrade: websocketConnection: Upgrade

This is the core of WebSocket, tell Apache, Nginx and other servers for protocol conversion

Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13

First, Sec-websocket-key is the value of a Base64 encode, which is randomly generated by the browser, telling the server to verify the WebSocket protocol.
Then, Sec_websocket-protocol is a user-defined string used to distinguish between the protocols required for different services under the same URL.

The data format returned by the server after receiving the message is similar:

HTTP/1.1 101     Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=Sec-WebSocket-Accept

The value of the server is returned to the client after it is computed with a client-consistent key.

http/1.1 101 Switching protocols indicates that the server accepts a client connection to the WebSocket protocol, and after such request-response processing, the WebSocket connection handshake on both ends succeeds, and subsequent TCP traffic can be made. Users can consult the WebSocket protocol stack for a more detailed interactive data format between the WebSocket client and the server.

On the development side, the WebSocket API is simple: simply instantiate the WebSocket, create the connection, and the server and the client can send and respond to each other. Detailed WebSocket API and code implementations can be found in the WebSocket implementation and Case Analysis section.


The Websokect in Golang

Github.com/gorilla/websocket

The main use of Github.com/gorilla/websocket this package in the project.

Through the above description of the WebSocket principle can be known, HTTP to WebSocket has a protocol conversion process, focusing on Upgrade server protocol conversion function.

Upgrade upgrades the HTTP server connection to the WebSocket protocol.////the Responseheader are included in the Respon SE to the client ' s upgrade//request. Use the Responseheader to specify Cookies (Set-cookie) and the//application negotiated Subprotocol (Sec-websocket-protoco L).////If The upgrade fails, then upgrade replies to the client with an HTTP error//response.func (U *upgrader) Upgrade ( W http. Responsewriter, R *http. Request, Responseheader http. Header) (*conn, error) {if R.method! = "GET" {return U.returnerror (W, R, HTTP). statusmethodnotallowed, "Websocket:not a websocket Handshake:request method is not GET")} If _, OK: = Respons eheader["Sec-websocket-extensions"]; OK {return U.returnerror (W, R, HTTP).        Statusinternalservererror, "websocket:application specific ' sec-websocket-extensions ' headers is unsupported")} If!tokenlistcontainsvalue (R.header, "Connection", "Upgrade") {return U.returnerror (W, R, HTTP). StatusbadrequesT, "Websocket:not a websocket handshake: ' Upgrade ' token not found in ' Connection ' header")} if!tokenlistcont Ainsvalue (R.header, "Upgrade", "WebSocket") {return U.returnerror (W, R, HTTP). Statusbadrequest, "Websocket:not a websocket handshake: ' websocket ' token not found in ' Upgrade ' header")} if !tokenlistcontainsvalue (R.header, "sec-websocket-version", "G") {return U.returnerror (W, R, HTTP). Statusbadrequest, "websocket:unsupported version:13 not found in ' sec-websocket-version ' header")} Checkorigi N: = U.checkorigin if Checkorigin = = Nil {checkorigin = checksameorigin} if!checkorigin (r) {RET Urn U.returnerror (W, R, http. Statusforbidden, "WebSocket: ' Origin ' header value not allowed")} Challengekey: = R.header.get ("Sec-websocket-k EY ") If Challengekey = =" "{return U.returnerror (W, R, HTTP). Statusbadrequest, "Websocket:not a websocket handshake: ' Sec-websocket-key ' header is missing or bLank ")} Subprotocol: = U.selectsubprotocol (R, Responseheader)//Negotiate pmce var compress bool If U.enablecompression {for _, Ext: = Range Parseextensions (r.header) {if ext[""]! = "Permessage-defla TE "{continue} compress = True Break}} var (n Etconn Net. Conn err Error) H, OK: = W. (http. Hijacker) if!ok {return U.returnerror (W, R, http. Statusinternalservererror, "Websocket:response does not implement HTTP. Hijacker ")} var BRW *bufio. Readwriter Netconn, BRW, err = H.hijack () if err! = Nil {return U.returnerror (W, R, HTTP). Statusinternalservererror, Err. Error ())} if BRW. reader.buffered () > 0 {netconn.close () return nil, errors. New ("Websocket:client sent data before handshake is complete")} c: = NEWCONNBRW (Netconn, True, U.readbuffersiz E, U.writebuffersize, BRW) C.subprotocOL = Subprotocol If compress {c.newcompressionwriter = Compressnocontexttakeover C.newdecompressionr Eader = Decompressnocontexttakeover} p: = c.writebuf[:0] p = append (P, "http/1.1 101 switching protocols\r\n    Upgrade:websocket\r\nconnection:upgrade\r\nsec-websocket-accept: "...)    p = Append (P, Computeacceptkey (Challengekey) ...)    p = Append (p, "\ r \ n" ...)        If C.subprotocol! = "" {p = append (P, "Sec-websocket-protocol:" ...)        p = Append (P, c.subprotocol ...)    p = Append (p, "\ r \ n" ...) } if compress {p = append (P, "sec-websocket-extensions:permessage-deflate; Server_no_context_takeover;    client_no_context_takeover\r\n "...)  } for k, vs: = Range Responseheader {if k = = ' Sec-websocket-protocol ' {continue} for            _, V: = Range vs {p = append (P, K ...)            p = Append (P, ":" ...) For I: = 0; I < Len (v); i++ {b: = V[i] If b <= {//Prevent response splitting.        b = '} p = append (p, b)} p = Append (p, "\ r \ n" ...)        }} p = Append (p, "\ r \ n" ...)    Clear deadlines set by HTTP server. Netconn.setdeadline (time. time{}) If U.handshaketimeout > 0 {netconn.setwritedeadline (time. Now (). ADD (u.handshaketimeout))} if _, err = Netconn.write (p); Err! = Nil {netconn.close () return nil, err} if u.handshaketimeout > 0 {netconn.setwrited Eadline (time. time{})} return C, nil}

This function allows you to see the approximate process:

    • Determines whether the request method is a get, not a get or an illegal handshake method
    • Confirm the upgrade protocol based on client's request header information
    • Verifying cross-domain
    • Populate the response header, respond back to the client, link build

Specific implementation

Server Side

The main use of upgrade function for protocol conversion. The Readbuffersize, writebuffersize, handshaketimeout parameters are specified, and cross-domain is called the default check function, and the custom check function always returns true to skip the cross-domain checksum

//controllertype MyWebSocketController struct {    beego.Controller}var upgrader = websocket.Upgrader{    ReadBufferSize:   1024,    WriteBufferSize:  1024,    HandshakeTimeout: 5 * time.Second,    CheckOrigin: func(r *http.Request) bool {        return true    },}func (c *MyWebSocketController) Get() {    ws, err := upgrader.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil)    if err != nil {        log.Fatal(err)    }    socket.Clients.Set(ws, true)    _, body, _ := ws.ReadMessage()    msg := socket.Message{Message: string(body)}    socket.Broadcast <- msg}

Message processing and forwarding

var (    Clients   = make(map[*websocket.Conn]bool, 1024)    Broadcast = make(chan Message, 1024))type Message struct {    Message string `json:"message"`}func init() {    go handleMessages()}//广播发送至页面func handleMessages() {    for {        msg := <-Broadcast        for client := range Clients {            err := client.WriteJSON(msg)            if err != nil {                client.Close()                delete(Clients, client)            }        }    }}

Route registration (annotated route with Beego cannot complete protocol conversion, not yet found)

beego.Router("/ws", &noticeMq.MyWebSocketController{})

Go Client

Send a message with the Golang.org/x/net/websocket package from Golang

package websocketimport (    "net/url"    "github.com/astaxie/beego"    "golang.org/x/net/websocket")type Client struct {    Host string    Path string}func NewWebsocketClient(host, path string) *Client {    return &Client{        Host: host,        Path: path,    }}func (this *Client) SendMessage(body []byte) error {    u := url.URL{Scheme: "ws", Host: this.Host, Path: this.Path}    ws, err := websocket.Dial(u.String(), "", "http://"+this.Host+"/")    defer ws.Close() //关闭连接    if err != nil {        beego.Error(err)        return err    }    _, err = ws.Write(body)    if err != nil {        beego.Error(err)        return err    }    return nil}

JS Client

Current mainstream browsers support WebSocket protocol (ie + +)

  <! DOCTYPE html> 
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.