We welcome you to subscribe, read, comment and like!!!!

preface

The sound of rain, accompanied by the sound of cars outside the window. In my heart, I think about my dreams and thoughts.

Today, we are going to talk about Websocket usage in GoLang. For example, learning Java Websocket may require a careful learning process. Today, we’re just gonna get our heads together,

Learn to walk!

WebSocket

First, let’s learn what WebSocket is. Here is an excerpt from Baidu Baike.

WebSocket is a protocol for full duplex communication over a single TCP connection. The WebSocket communication protocol was standardized by THE IETF in 2011 as RFC 6455, and is supplemented by RFC7936. The WebSocket API is also a W3C standard.

WebSocket makes it easier to exchange data between the client and the server, allowing the server to actively push data to the client. In the WebSocket API, the browser and server only need to complete a handshake to create a persistent connection and two-way data transfer.

Gorilla Websocket

Write webSocket client/server functionality in Go and use Gorilla WebSocket package in GoLang. The main repository code is on Github.

Now let’s see how Gorilla can be used to quickly set up a testable Websocket application.

Install Gorilla Websocket Go software package

There are no dependencies other than a runnable Go compiler, so you just need to use Go Get!

go get github.com/gorilla/websocket
Copy the code

Websocket application design

Before proceeding with any of the examples, let’s first design a rough layout of what needs to be done.

Any application that uses the WebSocket protocol usually requires a client and a server.

The server program binds to a port on the server and starts listening for any Websocket connections. The details about the connection are defined by the WebSocket protocol, which acts over the raw HTTP connection.

The client program attempts to establish a connection with the server using the Websocket URL. Note that while Gorilla provides us with an API for writing clients, Golang is not required to implement client programs.

If your Web application uses a separate front end, typically the Websocket client will be implemented in that language (Javascript, etc.).

However, for illustrative purposes, we will write both client and server programs in Go.

Now let’s get our client-server architecture running!

We will provide a program for the server.go server and the client.go client.

Using Gorilla Websockets – create our server

The WebSocket server will be implemented on a regular HTTP server. We use NET/HTTP to provide raw HTTP connections.

Now, in server.go, let’s write a regular HTTP server and add a socketHandler() function to handle the Websocket logic.

// server.go
package main
 
import (
    "log"
    "net/http"
    "time"
 
    "github.com/gorilla/websocket"
)
 
var upgrader = websocket.Upgrader{} // use default options
 
func socketHandler(w http.ResponseWriter, r *http.Request) {
    // Upgrade our raw HTTP connection to a websocket based one
    conn, err := upgrader.Upgrade(w, r, nil)
    iferr ! =nil {
        log.Print("Error during connection upgradation:", err)
        return
    }
    defer conn.Close()
 
    // The event loop
    for {
        messageType, message, err := conn.ReadMessage()
        iferr ! =nil {
            log.Println("Error during message reading:", err)
            break
        }
        log.Printf("Received: %s", message)
        err = conn.WriteMessage(messageType, message)
        iferr ! =nil {
            log.Println("Error during message writing:", err)
            break}}}func home(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Index Page")}func main(a) {
    http.HandleFunc("/socket", socketHandler)
    http.HandleFunc("/", home)
    log.Fatal(http.ListenAndServe("localhost:8080".nil))}Copy the code

Gorilla’s job is to convert the original HTTP connection into a stateful Websocket connection.

That’s why the struct calls Upgrader help us.

We use the global upgrader variable to help us convert any incoming HTTP connection to the Websocket protocol upgrader.upgrade (). This will return us *websocket.Connection, which we can now use to handle webSocket connections.

The server uses read messages and then uses conn.readMessage () to write messages conn.writemessage ()

The server simply echoes all incoming Websocket messages back to the client, so this illustrates how Websocket can be used for full-duplex communication.

Now let’s switch to the client that implements client.go.

Create our client program

We’ll also write the client in Gorilla. This simple client will continuously send messages every one second. If our entire system works as expected, the server will receive packets at one-second intervals and reply with the same message.

The client will also have the capability to receive incoming Websocket packets. In our program, we will have a separate Goroutine handler receiveHandler that listens for these incoming packets.

// client.go
package main
 
import (
    "log"
    "os"
    "os/signal"
    "time"
 
    "github.com/gorilla/websocket"
)
 
var done chan interface{}
var interrupt chan os.Signal
 
func receiveHandler(connection *websocket.Conn) {
    defer close(done)
    for {
        _, msg, err := connection.ReadMessage()
        iferr ! =nil {
            log.Println("Error in receive:", err)
            return
        }
        log.Printf("Received: %s\n", msg)
    }
}
 
func main(a) {
    done = make(chan interface{}) // Channel to indicate that the receiverHandler is done
    interrupt = make(chan os.Signal) // Channel to listen for interrupt signal to terminate gracefully
 
    signal.Notify(interrupt, os.Interrupt) // Notify the interrupt channel for SIGINT
 
    socketUrl := "ws://localhost:8080" + "/socket"
    conn, _, err := websocket.DefaultDialer.Dial(socketUrl, nil)
    iferr ! =nil {
        log.Fatal("Error connecting to Websocket Server:", err)
    }
    defer conn.Close()
    go receiveHandler(conn)
 
    // Our main loop for the client
    // We send our relevant packets here
    for {
        select {
        case <-time.After(time.Duration(1) * time.Millisecond * 1000) :// Send an echo packet every second
            err := conn.WriteMessage(websocket.TextMessage, []byte("Hello from GolangDocs!"))
            iferr ! =nil {
                log.Println("Error during writing to websocket:", err)
                return
            }
 
        case <-interrupt:
            // We received a SIGINT (Ctrl + C). Terminate gracefully...
            log.Println("Received SIGINT interrupt signal. Closing all pending connections")
 
            // Close our websocket connection
            err := conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
            iferr ! =nil {
                log.Println("Error during closing websocket:", err)
                return
            }
 
            select {
            case <-done:
                log.Println("Receiver Channel Closed! Exiting....")
            case <-time.After(time.Duration(1) * time.Second):
                log.Println("Timeout in closing receiving channel. Exiting....")}return
        }
Copy the code

If you look at the code, you’ll see that I created two channels done, interrupt for receiveHandler() and communication between main().

We use an infinite loop using SELECT to listen for events over a channel. We conn.writemessage () write a message every second. If the interrupt signal is activated, all pending connections are closed and we can exit normally!

Nested select ensures two things:

  • ifreceiveHandlerIf the channel exits, the channel'done'Will be closed. This is the first onecase <-doneconditions
  • if'done'If the channel is not closed, there will be a timeout after 1 second, so the program will exit after a timeout of 1 second

By carefully handling all case select using channels, you can have a minimal architecture that can be easily extended.

Finally, let’s look at the output we get when we run both the client and the server!

The output

conclusion

Learning is a continuous thing, and we learned about Websocket today.

Refueling comrades, constant efforts!!