The Message object

HTTP is a stream protocol. Web sockets are frame-based. You prepare a block of data (of any size) and send it as a set of frames. Frames can contain either strings in UTF-8 encoding or a sequence of bytes.

The simplest way of using web sockets is just to prepare a block of data and ask the Go websocket library to package it as a set of frame data, send them across the wire and receive it as the same block. The websocket package contains a convenience object Message to do just that. The Message object has two methods, Send and Receive which take a websocket as first parameter. The second parameter is either the address of a variable to store data in, or the data to be sent. Code to send string data would look like

  1. msgToSend := "Hello"
  2. err := websocket.Message.Send(ws, msgToSend)
  3. var msgToReceive string
  4. err := websocket.Message.Receive(conn, &msgToReceive)

Code to send byte data would look like

  1. dataToSend := []byte{0, 1, 2}
  2. err := websocket.Message.Send(ws, dataToSend)
  3. var dataToReceive []byte
  4. err := websocket.Message.Receive(conn, &dataToReceive)

An echo server to send and receive string data is given below. Note that in web sockets either side can initiate sending of messages, and in this server we send messages from the server to a client when it connects (send/receive) instead of the more normal receive/send server. The server is

  1. /* EchoServer
  2. */
  3. package main
  4. import (
  5. "fmt"
  6. "net/http"
  7. "os"
  8. // "io"
  9. "golang.org/x/net/websocket"
  10. )
  11. func Echo(ws *websocket.Conn) {
  12. fmt.Println("Echoing")
  13. for n := 0; n < 10; n++ {
  14. msg := "Hello " + string(n+48)
  15. fmt.Println("Sending to client: " + msg)
  16. err := websocket.Message.Send(ws, msg)
  17. if err != nil {
  18. fmt.Println("Can't send")
  19. break
  20. }
  21. var reply string
  22. err = websocket.Message.Receive(ws, &reply)
  23. if err != nil {
  24. fmt.Println("Can't receive")
  25. break
  26. }
  27. fmt.Println("Received back from client: " + reply)
  28. }
  29. }
  30. func main() {
  31. http.Handle("/", websocket.Handler(Echo))
  32. err := http.ListenAndServe(":12345", nil)
  33. checkError(err)
  34. }
  35. func checkError(err error) {
  36. if err != nil {
  37. fmt.Println("Fatal error ", err.Error())
  38. os.Exit(1)
  39. }
  40. }

A client that talks to this server is

  1. /* EchoClient
  2. */
  3. package main
  4. import (
  5. "golang.org/x/net/websocket"
  6. "fmt"
  7. "io"
  8. "os"
  9. )
  10. func main() {
  11. if len(os.Args) != 2 {
  12. fmt.Println("Usage: ", os.Args[0], "ws://host:port")
  13. os.Exit(1)
  14. }
  15. service := os.Args[1]
  16. conn, err := websocket.Dial(service, "", "http://localhost")
  17. checkError(err)
  18. var msg string
  19. for {
  20. err := websocket.Message.Receive(conn, &msg)
  21. if err != nil {
  22. if err == io.EOF {
  23. // graceful shutdown by server
  24. break
  25. }
  26. fmt.Println("Couldn't receive msg " + err.Error())
  27. break
  28. }
  29. fmt.Println("Received from server: " + msg)
  30. // return the msg
  31. err = websocket.Message.Send(conn, msg)
  32. if err != nil {
  33. fmt.Println("Coduln't return msg")
  34. break
  35. }
  36. }
  37. os.Exit(0)
  38. }
  39. func checkError(err error) {
  40. if err != nil {
  41. fmt.Println("Fatal error ", err.Error())
  42. os.Exit(1)
  43. }
  44. }

The url for the client running on the same machine as the server should be ws://localhost:12345/