I found myself wanting to try out little bit of experimenting to learn more about web sockets, let us try it out using golang and react.
First, set up a project Golang project by creating a folder and in it, create main.go file.
Golang WebSocket Server
It’s very simple if you take use of the already great crates that are out there. One that I found working out very well with web socket is gorilla websocket.
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func main() {
http.HandleFunc("/ws", wsEndpoint)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func wsEndpoint(w http.ResponseWriter, r *http.Request) {
upgrader.CheckOrigin = func(r *http.Request) bool { return true }
// upgrade this connection to a WebSocket
// connection
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
}
log.Println("Client Connected")
err = ws.WriteMessage(1, []byte("Hello client you've connected!"))
if err != nil {
log.Println(err)
}
reader(ws)
}
func reader(conn *websocket.Conn) {
for {
// read in a message
messageType, p, err := conn.ReadMessage()
if err != nil {
log.Println(err)
return
}
// print out incoming message
fmt.Println("incoming message: " + string(p))
if err := conn.WriteMessage(messageType, p); err != nil {
log.Println(err)
return
}
}
}
You should be able to run your program from the get-go. This is how the mod file looks:
module example.com/m/v2
go 1.15
require github.com/gorilla/websocket v1.5.0 // indirect
http.HandleFunc("/ws", wsEndpoint)
So let’s go through the code, first of all we got a main function, the starting point of the program and in it will first of all take use of the http package and set up our listeners for the endpoint /ws, which we pass in the method wsEndpoint. So each
log.Fatal(http.ListenAndServe(":8080", nil))
The ListenAndServe function will be running our actual http server and we will print out error if we get one into the log.
func wsEndpoint(w http.ResponseWriter, r *http.Request) {
upgrader.CheckOrigin = func(r *http.Request) bool { return true }
// upgrade this connection to a WebSocket
// connection
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
}
log.Println("Client Connected")
err = ws.WriteMessage(1, []byte("Hi Client!"))
if err != nil {
log.Println(err)
}
reader(ws)
}
Our Endpoint function takes in a ResponseWriter and a Request object which is what we need to make to make the incoming request into a websocket protocol connection with our server. This is called that we do an upgrade. From the upgrade function we get back a ws connection which we can read messages from.
func reader(conn *websocket.Conn) {
for {
// read in a message
messageType, p, err := conn.ReadMessage()
if err != nil {
log.Println(err)
return
}
// print out incoming message
fmt.Println("incoming message: " + string(p))
if err := conn.WriteMessage(messageType, p); err != nil {
log.Println(err)
return
}
}
}
From our reader function we can read the message from the websocket which we convert from bytes into string with help from string(p), which we then can send a response back with WriteMessage on the same socket to the client.
React WebSocket Client
Now let’s create a React project, I like to use vite to get started fast like this:
npm create vite@latest
Then go with React and nativescript. Then what web socket package I use is websocket from here: https://www.npmjs.com/package/websocket. Also remember to download the types for typescript: node_modules/@types/websocket. So we will run npm install on these:
npm i websocket
npm i node_modules/@types/websocket
Then in our React main.tsx let’s write some code where we connect to the server and send a random message for testing:
import { useEffect, useState } from 'react'
import logo from './logo.svg'
import './App.css'
import * as WebSocket from "websocket"
function App() {
useEffect(() => {
console.log("in it")
const socket = new WebSocket.w3cwebsocket('ws://localhost:8080/ws');
socket.onopen = function () {
socket.send("helloheee!")
socket.onmessage = (msg: any) => {
console.log(msg);
console.log("we got msg..")
};
};
}, []);
const [count, setCount] = useState(0)
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>Hello Vite + React!</p>
<p>
<button type="button" onClick={() => setCount((count) => count + 1)}>
count is: {count}
</button>
</p>
<p>
Edit <code>App.tsx</code> and save to test HMR updates.
</p>
<p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
{' | '}
<a
className="App-link"
href="https://vitejs.dev/guide/features.html"
target="_blank"
rel="noopener noreferrer"
>
Vite Docs
</a>
</p>
</header>
</div>
)
}
export default App
Also worth noting, inside the main.tsx I removed the StrictMode elements
<React.StrictMode>
if I didn’t it would trigger the user effect twice for some reason. Anyway that’s it to get started fast with a web socket to start experimenting. Hope coding!
I like this!
Glad to hear it!