JSON

This section adds nothing new to the earlier concepts. It just uses a different “wire” format for the data, JSON instead of gob. As such, clients or servers could be written in other languasge that understand sockets and JSON.

JSON RPC client

A client that calls both functions of the arithmetic server is

  1. /* JSONArithCLient
  2. */
  3. package main
  4. import (
  5. "net/rpc/jsonrpc"
  6. "fmt"
  7. "log"
  8. "os"
  9. )
  10. type Args struct {
  11. A, B int
  12. }
  13. type Quotient struct {
  14. Quo, Rem int
  15. }
  16. func main() {
  17. if len(os.Args) != 2 {
  18. fmt.Println("Usage: ", os.Args[0], "server:port")
  19. log.Fatal(1)
  20. }
  21. service := os.Args[1]
  22. client, err := jsonrpc.Dial("tcp", service)
  23. if err != nil {
  24. log.Fatal("dialing:", err)
  25. }
  26. // Synchronous call
  27. args := Args{17, 8}
  28. var reply int
  29. err = client.Call("Arith.Multiply", args, &reply)
  30. if err != nil {
  31. log.Fatal("arith error:", err)
  32. }
  33. fmt.Printf("Arith: %d*%d=%d\n", args.A, args.B, reply)
  34. var quot Quotient
  35. err = client.Call("Arith.Divide", args, &quot)
  36. if err != nil {
  37. log.Fatal("arith error:", err)
  38. }
  39. fmt.Printf("Arith: %d/%d=%d remainder %d\n", args.A, args.B, quot.Quo, quot.Rem)
  40. }

JSON RPC server

A version of the server that uses JSON encoding is

  1. /* JSONArithServer
  2. */
  3. package main
  4. import (
  5. "fmt"
  6. "net/rpc"
  7. "net/rpc/jsonrpc"
  8. "os"
  9. "net"
  10. "errors"
  11. )
  12. //import ("fmt"; "rpc"; "os"; "net"; "log"; "http")
  13. type Args struct {
  14. A, B int
  15. }
  16. type Quotient struct {
  17. Quo, Rem int
  18. }
  19. type Arith int
  20. func (t *Arith) Multiply(args *Args, reply *int) error {
  21. *reply = args.A * args.B
  22. return nil
  23. }
  24. func (t *Arith) Divide(args *Args, quo *Quotient) error {
  25. if args.B == 0 {
  26. return errors.New("divide by zero")
  27. }
  28. quo.Quo = args.A / args.B
  29. quo.Rem = args.A % args.B
  30. return nil
  31. }
  32. func main() {
  33. arith := new(Arith)
  34. rpc.Register(arith)
  35. tcpAddr, err := net.ResolveTCPAddr("tcp", ":1234")
  36. checkError(err)
  37. listener, err := net.ListenTCP("tcp", tcpAddr)
  38. checkError(err)
  39. /* This works:
  40. rpc.Accept(listener)
  41. */
  42. /* and so does this:
  43. */
  44. for {
  45. conn, err := listener.Accept()
  46. if err != nil {
  47. continue
  48. }
  49. jsonrpc.ServeConn(conn)
  50. }
  51. }
  52. func checkError(err error) {
  53. if err != nil {
  54. fmt.Println("Fatal error ", err.Error())
  55. os.Exit(1)
  56. }
  57. }

Conclusion

RPC is a popular means of distributing applications. Several ways of doing it have been presented here. What is missing from Go is support for the currently fashionable (but extremely badly enginereed) SOAP RPC mechanism.