...

/

Solution 4: Building Web Services

Solution 4: Building Web Services

Let’s solve the challenge set in the previous lesson.

We'll cover the following...

Solution

Here’s a simple implementation of ab(1) using goroutines and channels in Go.

To run the server side of the ab(1) utility, open a new terminal window and copy and paste the following command into the terminal:

python3 -m http.server 8082

To run the client side, copy and paste the following command into the other terminal window:

go run ab.go -url http://localhost:8082 -c 5 -n 10

Execute the server and client sides in the following playground:

package main

import (
	"flag"
	"fmt"
	"net/http"
	"sync"
	"io"
	"time"
)

func main() {
	// Parse command line flags
	var (
		concurrency int
		requests    int
		url         string
	)
	flag.IntVar(&concurrency, "c", 1, "Number of multiple requests to make at a time")
	flag.IntVar(&requests, "n", 1, "Number of requests to perform")
	flag.StringVar(&url, "url", "", "URL to test")
	flag.Parse()

	if url == "" {
		fmt.Println("Error: URL is required")
		return
	}

	// Create a channel to track completed requests
	done := make(chan bool)

	// Create a wait group to synchronize goroutines
	var wg sync.WaitGroup

	// Start timing the requests
	start := time.Now()

	// Launch the requested number of goroutines
	for i := 0; i < requests; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()

			// Make the HTTP request
			resp, err := http.Get(url)
			if err != nil {
				fmt.Println("Error making request:", err)
				return
			}
			defer resp.Body.Close()

			// Read the response body to completion to simulate a real-world scenario
			_, _ = io.ReadAll(resp.Body)

			// Notify that the request is done
			done <- true
		}()

		// Limit the concurrency
		if i%concurrency == 0 {
			time.Sleep(time.Millisecond * 10)
		}
	}

	// Calculate and print the results
	duration := time.Since(start)
	reqsPerSec := float64(requests) / duration.Seconds()
	fmt.Println("Concurrency Level: %d\n", concurrency)
	fmt.Printf("Time taken for tests: %v seconds\n", duration.Seconds())
	fmt.Printf("Complete requests: %d\n", requests)
	fmt.Printf("Requests per second: %.2f [#/sec]\n", reqsPerSec)
}
ab.go

Code explanation

  • Lines 3–9: These are the package imports. The flag package provides a ...