These steps cover writing and running your application:
- From your Terminal or console application, create a new directory called ~/projects/go-programming-cookbook/chapter5/websocket and navigate to this directory.
- Run the following command:
$ go mod init github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter5/websocket
You should see a file called go.mod that contains the following:
module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter5/websocket
- Copy tests from ~/projects/go-programming-cookbook-original/chapter5/websocket or use this as an exercise to write some of your own code!
- Create a new directory named server and navigate to it.
- Create a file called handler.go with the following content:
package main
import (
"log"
"net/http"
"github.com/gorilla/websocket"
)
// upgrader takes an http connection and converts it
// to a websocket one, we're using some recommended
// basic buffer sizes
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func wsHandler(w http.ResponseWriter, r *http.Request) {
// upgrade the connection
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("failed to upgrade connection: ", err)
return
}
for {
// read and echo back messages in a loop
messageType, p, err := conn.ReadMessage()
if err != nil {
log.Println("failed to read message: ", err)
return
}
log.Printf("received from client: %#v", string(p))
if err := conn.WriteMessage(messageType, p); err != nil {
log.Println("failed to write message: ", err)
return
}
}
}
- Create a file called main.go with the following content:
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
fmt.Println("Listening on port :8000")
// we mount our single handler on port localhost:8000 to handle all
// requests
log.Panic(http.ListenAndServe("localhost:8000", http.HandlerFunc(wsHandler)))
}
- Navigate to the previous directory.
- Create a new directory named client and navigate to it.
- Create a file called process.go with the following content:
package main
import (
"bufio"
"fmt"
"log"
"os"
"strings"
"github.com/gorilla/websocket"
)
func process(c *websocket.Conn) {
reader := bufio.NewReader(os.Stdin)
for {
fmt.Printf("Enter some text: ")
// this will block ctrl-c, to exit press it then hit enter
// or kill from another location
data, err := reader.ReadString(' ')
if err != nil {
log.Println("failed to read stdin", err)
}
// trim off the space from reading the string
data = strings.TrimSpace(data)
// write the message as a byte across the websocket
err = c.WriteMessage(websocket.TextMessage, []byte(data))
if err != nil {
log.Println("failed to write message:", err)
return
}
// this is an echo server, so we can always read after the write
_, message, err := c.ReadMessage()
if err != nil {
log.Println("failed to read:", err)
return
}
log.Printf("received back from server: %#v ", string(message))
}
}
- Create a file called main.go with the following content:
package main
import (
"log"
"os"
"os/signal"
"github.com/gorilla/websocket"
)
// catchSig cleans up our websocket connection
// if we kill the program with a Ctrl + C
func catchSig(ch chan os.Signal, c *websocket.Conn) {
// block on waiting for a signal
<-ch
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("write close:", err)
}
return
}
func main() {
// connect the os signal to our channel
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
// use the ws:// Scheme to connect to the websocket
u := "ws://localhost:8000/"
log.Printf("connecting to %s", u)
c, _, err := websocket.DefaultDialer.Dial(u, nil)
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close()
// dispatch our signal catcher
go catchSig(interrupt, c)
process(c)
}
- Navigate to the previous directory.
- Run go run ./server and you will see the following output:
$ go run ./server
Listening on port :8000
- In a separate Terminal, run go run ./client from the websocket directory and you will see the following output:
$ go run ./client
2019/05/26 11:53:20 connecting to ws://localhost:8000/
Enter some text:
- Enter the test string and you should see the following:
$ go run ./client
2019/05/26 11:53:20 connecting to ws://localhost:8000/
Enter some text: test
2019/05/26 11:53:22 received back from server: "test"
Enter some text:
- Navigate to the Terminal running the server and you should see something similar to the following:
$ go run ./server
Listening on port :8000
2019/05/26 11:53:22 received from client: "test"
- Press Ctrl + C to exit both the server and client. You may also have to hit Enter after pressing Ctrl + C on the client.
- The go.mod file may be updated and the go.sum file should now be present in the top-level recipe directory.
- If you copied or wrote your own tests, go up one directory and run go test. Ensure that all the tests pass.