添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
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) if err != nil { log.Print("Error during connection upgradation:", err) return defer conn.Close() // The event loop for { messageType, message, err := conn.ReadMessage() if err != nil { log.Println("Error during message reading:", err) break log.Printf("Received: %s", message) err = conn.WriteMessage(messageType, message) if err != nil { log.Println("Error during message writing:", err) break func home(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Index Page") func main() { http.HandleFunc("/socket", socketHandler) http.HandleFunc("/", home) log.Fatal(http.ListenAndServe("localhost:8080", nil))

The magic that gorilla does is to convert these raw HTTP connections into a stateful websocket connection, using a connection upgradation . This is why the library uses a struct called Upgrader to help us with that.

We use a global upgrader variable to help us convert any incoming HTTP connection into websocket protocol, via upgrader.Upgrade() . This will return to us a *websocket.Connection , which we can now use to deal with the websocket connection.

The server reads messages using conn.ReadMessage() and writes them back using conn.WriteMessage()

This server simply echoes any incoming websocket messages back to the client, so this shows how websockets can be used for full-duplex communication.

_, msg, err := connection.ReadMessage() if err != nil { log.Println("Error in receive:", err) return log.Printf("Received: %s\n", msg) func main() { 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) if err != 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!")) if err != 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, "")) if err != 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

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

We use an infinite loop for listening to events through channels using select . We write a message using conn.WriteMessage() every second. If the interrupt signal is activated, any pending connections are closed and we exit gracefully!

The nested select is there to ensure two things:

  • If the receiveHandler channel exits, the channel 'done' will be closed. This is the first case <-done condition
  • If the 'done' channel does NOT close, there will be a timeout after 1 second, so the program WILL exit after the 1 second timeout

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

Let’s finally look at the output we get, on running both the client and the server!

Sample Output

Go developer salary: factors impacting pay, job outlook, and how to create a perfect CV for this position Scraping Amazon Products Data using Golang Learning Golang with no programming experience Remote Debugging in Golang and Java Golang Read File Line by Line Golang Global Variables Techniques to Maximize Your Go Application’s Performance