I wrote a load test program to stress a web service, which runs fine on Linux.
However, on Windows it runs out of ports in net.Dial with this error:
Post http://localhost:9090: dial tcp [::1]:9090: connectex: Only one usage of each socket address (protocol/network address/port) is normally permitted.
I have tried changing the registry to increase the available port count and reducing the WAIT_TIME as described in this post: Success Center
Does anyone know if there is a way to re-use ports so that Windows doesn’t run out of ports (or some other way to achieve this load test)?
My code is below:
package main
import (
"bytes"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strconv"
"time"
)
type args struct {
url string
body []byte
threads int
}
func main() {
// 06-hammer url body threads
if len(os.Args) != 4 {
showUsage()
return
}
var arg args
arg.url = os.Args[1]
body := os.Args[2]
threads, err := strconv.Atoi(os.Args[3])
if err != nil || len(arg.url) < 1 || len(body) < 1 {
showUsage()
return
}
arg.threads = threads
arg.body, err = os.ReadFile(body)
if err != nil {
fmt.Printf("error reading '%v': %v \n", body, err)
return
}
call(arg)
}
func showUsage() {
fmt.Println("Usage:")
fmt.Println("06-hammer url body threads")
fmt.Println("Example:")
fmt.Println(`06-hammer http://localhost:9090 "./body.json" 10`)
}
func call(arg args) {
start := time.Now()
var succ int
var fail int
var attempt int
for {
c := parallel(arg)
attempt++
for i := 0; i < arg.threads; i++ {
result := <-c
if result {
succ++
} else {
fail++
}
}
if time.Since(start) >= time.Duration(time.Second*5) {
log.Printf("success: %v fail: %v elapsed: %v, avg: %v \n", succ, fail, time.Since(start), time.Duration(int64(time.Since(start))/int64(attempt)))
start = time.Now()
succ = 0
fail = 0
attempt = 0
}
}
}
func parallel(arg args) chan bool {
out := make(chan bool)
for i := 0; i < arg.threads; i++ {
go caller(arg, out)
}
return out
}
func caller(arg args, c chan bool) {
var defaultTransport http.RoundTripper = &http.Transport{Proxy: nil, DisableKeepAlives: true}
client := &http.Client{Transport: defaultTransport}
r, err := client.Post(arg.url, "application/json", bytes.NewReader(arg.body))
if err != nil {
c <- false
return
}
defer r.Body.Close()
_, err = ioutil.ReadAll(r.Body)
if err != nil {
c <- false
return
}
c <- true
}