一、概述

开发简单 web 服务程序 cloudgo,了解 web 服务器工作原理。

任务目标

  1. 熟悉 go 服务器工作原理
  2. 基于现有 web 库,编写一个简单 web 应用类似 cloudgo。
  3. 使用 curl 工具访问 web 程序
  4. 对 web 执行压力测试



二、系统环境&项目介绍

1.系统环境

操作系统:CentOS7
硬件信息:使用virtual box配置虚拟机(内存3G、磁盘30G)
编程语言:GO 1.15.2

2.项目的任务要求

(1)基本要求

  1. 编程 web 服务程序 类似 cloudgo 应用。
    • 支持静态文件服务
    • 支持简单 js 访问
    • 提交表单,并输出一个表格(必须使用模板)
  2. 使用 curl 测试,将测试结果写入 README.md
  3. 使用 ab 测试,将测试结果写入 README.md。并解释重要参数。

(2)扩展要求

选择以下一个或多个任务,以博客的形式提交。

  1. 通过源码分析、解释一些关键功能实现
  2. 选择简单的库,如 mux 等,通过源码分析、解释它是如何实现扩展的原理,包括一些 golang 程序设计技巧。


三、具体程序设计及Golang代码实现

1.预先准备

首先需要安装以下三个程序包:

[henryhzy@localhost ~]$ go get github.com/codegangsta/negroni
[henryhzy@localhost ~]$ go get github.com/gorilla/mux
[henryhzy@localhost ~]$ go get github.com/unrolled/render

下面我按照以下顺序来介绍简单web服务程序——CloudGo的程序设计:
①CloudGoClient.go的main函数
②CloudServer.go的NewServer函数
③CloudServer.go的initRoutes函数
④CloudServer.go的apiTestHandler函数
⑤CloudServer.go的homeHandler函数
⑥CloudServer.go的userHandler函数



2.CloudGoClient.go的main函数

借鉴课程博客1,编写CloudGoClient.go的main函数如下:

package main

import (
	"os"

	flag "github.com/spf13/pflag"
	"github.com/user/CloudGo/service"
)

const (
	PORT string = "2026"
)

func main() {
	port := os.Getenv("PORT")
	if len(port) == 0 {
		port = PORT
	}

	pPort := flag.StringP("port", "p", PORT, "PORT for httpd listening")
	flag.Parse()
	if len(*pPort) != 0 {
		port = *pPort
	}

	server := service.NewServer()
	server.Run(":" + port)
}



3.CloudServer.go的NewServer函数

借鉴课程博客2,编写CloudServer.go的NewServer函数如下:

// NewServer configures and returns a Server.
func NewServer() *negroni.Negroni {

	formatter := render.New(render.Options{
		Directory:  "templates",
		Extensions: []string{".html"},
		IndentJSON: true,
	})

	n := negroni.Classic()
	mx := mux.NewRouter()

	initRoutes(mx, formatter)

	n.UseHandler(mx)
	return n
}



4.CloudServer.go的initRoutes函数

借鉴课程博客2,编写CloudServer.go的initRoutes函数如下:

func initRoutes(mx *mux.Router, formatter *render.Render) {
	webRoot := os.Getenv("WEBROOT")
	if len(webRoot) == 0 {
		if root, err := os.Getwd(); err != nil {
			panic("Could not retrive working directory")
		} else {
			webRoot = root
			//fmt.Println(root)
		}
	}

	mx.HandleFunc("/api/test", apiTestHandler(formatter)).Methods("GET")
	mx.HandleFunc("/", homeHandler(formatter)).Methods("GET")
	mx.HandleFunc("/user", userHandler).Methods("POST")
	mx.PathPrefix("/").Handler(http.FileServer(http.Dir(webRoot + "/assets/")))
}



5.CloudServer.go的apiTestHandler函数

借鉴课程博客2,编写CloudServer.go的apiTestHandler函数如下:

//mx.HandleFunc("/api/test", apiTestHandler(formatter)).Methods("GET")

func apiTestHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		formatter.JSON(w, http.StatusOK, struct {
			ID      string `json:"id"`
			Content string `json:"content"`
		}{ID: "18342026", Content: "Hello from Go!"})
	}
}

其对应的js文件为apitest.js,内容如下:

$(document).ready(function() {
    $.ajax({
        url: "/api/test"
    }).then(function(data) {
       $('.ID').append(data.ID);
       $('.Content').append(data.Content);
    });
});



6.CloudServer.go的homeHandler函数

借鉴课程博客2,编写CloudServer.go的homeHandler函数如下:

//main
//mx.HandleFunc("/", homeHandler(formatter)).Methods("GET")

func homeHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		template := template.Must(template.New("home.html").ParseFiles("./templates/home.html"))
		_ = template.Execute(w, struct {
			ID      string
			Content string
		}{ID: "18342026", Content: "Welcome to CloudGo!!"})
	}
}

home对应的是网页的初始页面,需要再编写相对应的home.html和home.css,这里为了符合课程博客的“提交表单”要求,我将其设置为登录页面:

<html>

<head>
  <link rel="stylesheet" href="css/home.css" />
</head>

<body>
  <form class="box" action="./user" method="POST">
    <h1 class="Content">{{.Content}}</h1>
    <input type="text" name="username" placeholder="Username">
    <input type="password" name="password" placeholder="Password">
    <input type="submit" value="Sign In">
    <h4 class="Content">{{"Designed By HenryHZY, 18342026."}}</h4>
    <img src="files/nice picture.png" height="400" width="400"/>
  </form>
</body>

</html>



7.CloudServer.go的userHandler函数

借鉴课程博客2,编写CloudServer.go的userHandler函数如下:

func userHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	username := template.HTMLEscapeString(r.Form.Get("username"))
	password := template.HTMLEscapeString(r.Form.Get("password"))
	t := template.Must(template.New("user.html").ParseFiles("./templates/user.html"))
	err := t.Execute(w, struct {
		Username string
		Password string
		ID       string
		Motto    string
	}{Username: username, Password: password, ID: "18342026", Motto: "Stay hungry, stay foolish."})
	if err != nil {
		panic(err)
	}
}

user对应的是登录后跳转的页面,需要再编写相对应的user.html和user.css,这里为了符合课程博客的“输出一个表格”要求,我将其设置为对应的登录用户的个人信息:

<html>
    
<head>
    <link rel="stylesheet" href="css/user.css" />
</head>

<body>
    <table class="box" border="4">
        <tr>
            <td>Username</td>
            <td>{{.Username}}</td>
        </tr>
        <tr>
            <td>Password</td>
            <td>{{.Password}}</td>
        </tr>
        <tr>
            <td>ID</td>
            <td>{{.ID}}</td>
        </tr>
        <tr>
            <td>Motto</td>
            <td>{{.Motto}}</td>
        </tr>
    </table>
</body>

</html>



四、程序使用与测试

1.封装并使用程序包

在项目CloudGo的目录下,执行如下指令:

go install

在其他路径下建立main.go,并调用CloudGo库即可。



2.功能测试

功能测试主要从用户角度测试程序包的功能,在【三、具体程序设计及Golang代码实现】已设计了main函数,直接通过以下指令运行即可:

[henryhzy@localhost CloudGo]$ go run CloudGoClient.go

然后在浏览器中进入http://localhost:2026浏览即可,下面以项目的要求来演示功能测试结果。

编程 web 服务程序 类似 cloudgo 应用。
①支持静态文件服务
②支持简单 js 访问
③提交表单,并输出一个表格(必须使用模板)

①支持静态文件服务
进入http://localhost:2026/files:
在这里插入图片描述
访问图片文件:
在这里插入图片描述
访问文本文件:
在这里插入图片描述

②支持简单 js (JavaScript )访问
上文我借鉴课程博客2,设计了apiTestHandler函数。

这段代码非常简单,输出了一个 匿名结构,并 JSON (JavaScript Object Notation) 序列化输出。

进入http://localhost:2026/api/test:
在这里插入图片描述
可以使用其来进行筛选和查看原始数据等操作:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述



③提交表单,并输出一个表格(必须使用模板)

为了符合课程博客的要求,我将网页的初始页面设置为登录页面,需要输入username和password,再点击sign in按钮来实现“提交表单”;将登录后跳转的页面设置为显示对应的登录用户的个人信息表格,来实现“输出一个表格”。

此外根据博客要求,使用模板即使用html+css,此处已在【三、具体程序设计及Golang代码实现】中给出。

访问http://localhost:2026/:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述



3.curl连接测试

①curl -v http://localhost:2026/files

[henryhzy@localhost ~]$ curl -v http://localhost:2026/files
* About to connect() to localhost port 2026 (#0)
*   Trying ::1...
* Connected to localhost (::1) port 2026 (#0)
> GET /files HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:2026
> Accept: */*
> 
< HTTP/1.1 301 Moved Permanently
< Location: files/
< Date: Sun, 22 Nov 2020 12:37:50 GMT
< Content-Length: 0
< 
* Connection #0 to host localhost left intact

②curl -v http://localhost:2026/files/nice_text.txt

[henryhzy@localhost ~]$ curl -v http://localhost:2026/files/nice_text.txt
* About to connect() to localhost port 2026 (#0)
*   Trying ::1...
* Connected to localhost (::1) port 2026 (#0)
> GET /files/nice_text.txt HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:2026
> Accept: */*
> 
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Content-Length: 21
< Content-Type: text/plain; charset=utf-8
< Last-Modified: Sun, 22 Nov 2020 12:36:41 GMT
< Date: Sun, 22 Nov 2020 12:38:37 GMT
< 
* Connection #0 to host localhost left intact

③curl -v http://localhost:2026/api/test

[henryhzy@localhost ~]$ curl -v http://localhost:2026/api/test
* About to connect() to localhost port 2026 (#0)
*   Trying ::1...
* Connected to localhost (::1) port 2026 (#0)
> GET /api/test HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:2026
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=UTF-8
< Date: Sun, 22 Nov 2020 12:39:01 GMT
< Content-Length: 54
< 
{
  "id": "18342026",
  "content": "Hello from Go!"
}
* Connection #0 to host localhost left intact

④curl -v http://localhost:2026

[henryhzy@localhost ~]$ curl -v http://localhost:2026
* About to connect() to localhost port 2026 (#0)
*   Trying ::1...
* Connected to localhost (::1) port 2026 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:2026
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Sun, 22 Nov 2020 12:39:26 GMT
< Content-Length: 504
< Content-Type: text/html; charset=utf-8
< 
<html>

<head>
  <link rel="stylesheet" href="css/home.css" />
</head>

<body>
  <form class="box" action="./user" method="POST">
    <h1 class="Content">Welcome to CloudGo!!</h1>
    <input type="text" name="username" placeholder="Username">
    <input type="password" name="password" placeholder="Password">
    <input type="submit" value="Sign In">
    <h4 class="Content">Designed By HenryHZY, 18342026.</h4>
    <img src="files/nice picture.png" height="400" width="400"/>
  </form>
</body>

* Connection #0 to host localhost left intact

⑤curl -v http://localhost:2026/errorTest
此处是进行错误测试,当对应的网页不存在,便会返回404 NOT FOUND的错误信息。

[henryhzy@localhost ~]$ curl -v http://localhost:2026/errorTest
* About to connect() to localhost port 2026 (#0)
*   Trying ::1...
* Connected to localhost (::1) port 2026 (#0)
> GET /errorTest HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:2026
> Accept: */*
> 
< HTTP/1.1 404 Not Found
< Content-Type: text/plain; charset=utf-8
< X-Content-Type-Options: nosniff
< Date: Sun, 22 Nov 2020 12:40:20 GMT
< Content-Length: 19
< 
404 page not found
* Connection #0 to host localhost left intact



4.ab压力测试,并解释重要参数

①首先安装压力测试需要的软件:

[henryhzy@localhost ~]$ sudo yum -y install httpd-tools

②参数解释
输入ab -help:

[henryhzy@localhost ~]$ ab -help
Usage: ab [options] [http[s]://]hostname[:port]/path
Options are:
    -n requests     Number of requests to perform
    -c concurrency  Number of multiple requests to make at a time
    -t timelimit    Seconds to max. to spend on benchmarking
                    This implies -n 50000
    -s timeout      Seconds to max. wait for each response
                    Default is 30 seconds
    -b windowsize   Size of TCP send/receive buffer, in bytes
    -B address      Address to bind to when making outgoing connections
    -p postfile     File containing data to POST. Remember also to set -T
    -u putfile      File containing data to PUT. Remember also to set -T
    -T content-type Content-type header to use for POST/PUT data, eg.
                    'application/x-www-form-urlencoded'
                    Default is 'text/plain'
    -v verbosity    How much troubleshooting info to print
    -w              Print out results in HTML tables
    -i              Use HEAD instead of GET
    -x attributes   String to insert as table attributes
    -y attributes   String to insert as tr attributes
    -z attributes   String to insert as td or th attributes
    -C attribute    Add cookie, eg. 'Apache=1234'. (repeatable)
    -H attribute    Add Arbitrary header line, eg. 'Accept-Encoding: gzip'
                    Inserted after all normal header lines. (repeatable)
    -A attribute    Add Basic WWW Authentication, the attributes
                    are a colon separated username and password.
    -P attribute    Add Basic Proxy Authentication, the attributes
                    are a colon separated username and password.
    -X proxy:port   Proxyserver and port number to use
    -V              Print version number and exit
    -k              Use HTTP KeepAlive feature
    -d              Do not show percentiles served table.
    -S              Do not show confidence estimators and warnings.
    -q              Do not show progress when doing more than 150 requests
    -g filename     Output collected data to gnuplot format file.
    -e filename     Output CSV file with percentages served
    -r              Don't exit on socket receive errors.
    -h              Display usage information (this message)
    -Z ciphersuite  Specify SSL/TLS cipher suite (See openssl ciphers)
    -f protocol     Specify SSL/TLS protocol
                    (SSL3, TLS1, TLS1.1, TLS1.2 or ALL)
ab [options] url
-n	即requests,用于指定压力测试总共的执行次数。
-c	即concurrency,用于指定的并发数。
-t	即timelimit,等待响应的最大时间(单位:秒)。
-b	即windowsize,TCP发送/接收的缓冲大小(单位:字节)。
-p	即postfile,发送POST请求时需要上传的文件,此外还必须设置-T参数。
-u	即putfile,发送PUT请求时需要上传的文件,此外还必须设置-T参数。
-T	即content-type,用于设置Content-Type请求头信息,例如:application/x-www-form-urlencoded,默认值为text/plain。
-v	即verbosity,指定打印帮助信息的冗余级别。
-w	以HTML表格形式打印结果。
-i	使用HEAD请求代替GET请求。
-x	插入字符串作为table标签的属性。
-y	插入字符串作为tr标签的属性。
-z	插入字符串作为td标签的属性。
-C	添加cookie信息,例如:"Apache=1234"(可以重复该参数选项以添加多个)。
-H	添加任意的请求头,例如:"Accept-Encoding: gzip",请求头将会添加在现有的多个请求头之后(可以重复该参数选项以添加多个)。
-A	添加一个基本的网络认证信息,用户名和密码之间用英文冒号隔开。
-P	添加一个基本的代理认证信息,用户名和密码之间用英文冒号隔开。
-X	指定使用的和端口号,例如:"126.10.10.3:88"。
-V	打印版本号并退出。
-k	使用HTTP的KeepAlive特性。
-d	不显示百分比。
-S	不显示预估和警告信息。
-g	输出结果信息到gnuplot格式的文件中。
-e	输出结果信息到CSV格式的文件中。
-r	指定接收到错误信息时不退出程序。
-h	显示用法信息,其实就是ab -help。

此外,输出参数如下:

Server Software:        nginx/1.10.2 (服务器软件名称及版本信息)
Server Hostname:        192.168.1.106(服务器主机名)
Server Port:            80 (服务器端口)
Document Path:          /index1.html. (供测试的URL路径)
Document Length:        3721 bytes (供测试的URL返回的文档大小)
Concurrency Level:      1000 (并发数)
Time taken for tests:   2.327 seconds (压力测试消耗的总时间)
Complete requests:      5000 (的总次数)
Failed requests:        688 (失败的请求数)
Write errors:           0 (网络连接写入错误数)
Total transferred:      17402975 bytes (传输的总数据量)
HTML transferred:       16275725 bytes (HTML文档的总数据量)
Requests per second:    2148.98 [#/sec] (mean) (平均每秒的请求数) 这个是非常重要的参数数值,服务器的吞吐量 
Time per request:       465.338 [ms] (mean) (所有并发用户(这里是1000)都请求一次的平均时间)
Time  request:       0.247 [ms] (mean, across all concurrent requests) (单个用户请求一次的平均时间)
Transfer rate:          7304.41 [Kbytes/sec] received 每秒获取的数据长度 (传输速率,单位:KB/s)
...
Percentage of the requests served within a certain time (ms)
  50%    347  ## 50%的请求在347ms内返回 
  66%    401  ## 60%的请求在401ms内返回 
  75%    431
  80%    516
  90%    600
  95%    846
  98%   1571
  99%   1593
 100%   1619 (longest request)

③简单的压力测试
此处我主要使用-n和-c参数,即”用于指定压力测试总共的执行次数“和”用于指定的并发数“。另外,我们需要注意-c的数值需要小于或等于-n的数值。

(1)ab -n 2026 -c 10 http://localhost:2026/files

[henryhzy@localhost ~]$ ab -n 2026 -c 10 http://localhost:2026/files
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 202 requests
Completed 404 requests
Completed 606 requests
Completed 808 requests
Completed 1010 requests
Completed 1212 requests
Completed 1414 requests
Completed 1616 requests
Completed 1818 requests
Completed 2020 requests
Finished 2026 requests


Server Software:        
Server Hostname:        localhost
Server Port:            2026

Document Path:          /files
Document Length:        0 bytes

Concurrency Level:      10
Time taken for tests:   0.729 seconds
Complete requests:      2026
Failed requests:        0
Write errors:           0
Non-2xx responses:      2026
Total transferred:      218808 bytes
HTML transferred:       0 bytes
Requests per second:    2780.91 [#/sec] (mean)
Time per request:       3.596 [ms] (mean)
Time per request:       0.360 [ms] (mean, across all concurrent requests)
Transfer rate:          293.30 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       2
Processing:     1    3   4.0      1      24
Waiting:        0    3   4.0      1      23
Total:          1    4   4.0      2      24

Percentage of the requests served within a certain time (ms)
  50%      2
  66%      2
  75%      3
  80%      5
  90%      7
  95%     14
  98%     18
  99%     19
 100%     24 (longest request)

(2)ab -n 2026 -c 10 http://localhost:2026/files/nice_text.txt

[henryhzy@localhost ~]$ ab -n 2026 -c 10 http://localhost:2026/files/nice_text.txt
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 202 requests
Completed 404 requests
Completed 606 requests
Completed 808 requests
Completed 1010 requests
Completed 1212 requests
Completed 1414 requests
Completed 1616 requests
Completed 1818 requests
Completed 2020 requests
Finished 2026 requests


Server Software:        
Server Hostname:        localhost
Server Port:            2026

Document Path:          /files/nice_text.txt
Document Length:        21 bytes

Concurrency Level:      10
Time taken for tests:   0.725 seconds
Complete requests:      2026
Failed requests:        0
Write errors:           0
Total transferred:      417356 bytes
HTML transferred:       42546 bytes
Requests per second:    2793.84 [#/sec] (mean)
Time per request:       3.579 [ms] (mean)
Time per request:       0.358 [ms] (mean, across all concurrent requests)
Transfer rate:          562.04 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:     1    3   4.1      2      23
Waiting:        0    3   4.1      1      23
Total:          1    4   4.2      2      23

Percentage of the requests served within a certain time (ms)
  50%      2
  66%      2
  75%      3
  80%      4
  90%      8
  95%     16
  98%     18
  99%     19
 100%     23 (longest request)

(3)ab -n 2026 -c 10 http://localhost:2026/api/test

[henryhzy@localhost ~]$ ab -n 2026 -c 10 http://localhost:2026/api/test
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 202 requests
Completed 404 requests
Completed 606 requests
Completed 808 requests
Completed 1010 requests
Completed 1212 requests
Completed 1414 requests
Completed 1616 requests
Completed 1818 requests
Completed 2020 requests
Finished 2026 requests


Server Software:        
Server Hostname:        localhost
Server Port:            2026

Document Path:          /api/test
Document Length:        54 bytes

Concurrency Level:      10
Time taken for tests:   0.642 seconds
Complete requests:      2026
Failed requests:        0
Write errors:           0
Total transferred:      358602 bytes
HTML transferred:       109404 bytes
Requests per second:    3157.84 [#/sec] (mean)
Time per request:       3.167 [ms] (mean)
Time per request:       0.317 [ms] (mean, across all concurrent requests)
Transfer rate:          545.84 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.4      0       9
Processing:     1    3   3.4      1      18
Waiting:        0    3   3.4      1      18
Total:          1    3   3.5      2      22

Percentage of the requests served within a certain time (ms)
  50%      2
  66%      2
  75%      3
  80%      4
  90%      7
  95%     13
  98%     17
  99%     18
 100%     22 (longest request)

(4)ab -n 2026 -c 10 http://localhost:2026/

[henryhzy@localhost ~]$ ab -n 2026 -c 10 http://localhost:2026/
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 202 requests
Completed 404 requests
Completed 606 requests
Completed 808 requests
Completed 1010 requests
Completed 1212 requests
Completed 1414 requests
Completed 1616 requests
Completed 1818 requests
Completed 2020 requests
Finished 2026 requests


Server Software:        
Server Hostname:        localhost
Server Port:            2026

Document Path:          /
Document Length:        504 bytes

Concurrency Level:      10
Time taken for tests:   1.064 seconds
Complete requests:      2026
Failed requests:        0
Write errors:           0
Total transferred:      1258146 bytes
HTML transferred:       1021104 bytes
Requests per second:    1903.61 [#/sec] (mean)
Time per request:       5.253 [ms] (mean)
Time per request:       0.525 [ms] (mean, across all concurrent requests)
Transfer rate:          1154.44 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:     1    5   5.1      3      25
Waiting:        0    5   5.1      2      25
Total:          1    5   5.1      3      26

Percentage of the requests served within a certain time (ms)
  50%      3
  66%      4
  75%      5
  80%      8
  90%     11
  95%     18
  98%     23
  99%     24
 100%     26 (longest request)

(5)ab -n 2026 -c 10 http://localhost:2026/errorTest

Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 202 requests
Completed 404 requests
Completed 606 requests
Completed 808 requests
Completed 1010 requests
Completed 1212 requests
Completed 1414 requests
Completed 1616 requests
Completed 1818 requests
Completed 2020 requests
Finished 2026 requests


Server Software:        
Server Hostname:        localhost
Server Port:            2026

Document Path:          /errorTest
Document Length:        19 bytes

Concurrency Level:      10
Time taken for tests:   0.669 seconds
Complete requests:      2026
Failed requests:        0
Write errors:           0
Non-2xx responses:      2026
Total transferred:      356576 bytes
HTML transferred:       38494 bytes
Requests per second:    3028.19 [#/sec] (mean)
Time per request:       3.302 [ms] (mean)
Time per request:       0.330 [ms] (mean, across all concurrent requests)
Transfer rate:          520.47 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:     1    3   3.6      1      19
Waiting:        0    3   3.5      1      18
Total:          1    3   3.6      2      19

Percentage of the requests served within a certain time (ms)
  50%      2
  66%      2
  75%      3
  80%      4
  90%      7
  95%     13
  98%     17
  99%     18
 100%     19 (longest request)



五、完整代码

具体代码可见gitee仓库:gitee


六、扩展博客
(2)扩展要求

选择以下一个或多个任务,以博客的形式提交。

1. 通过源码分析、解释一些关键功能实现
2. 选择简单的库,如 mux 等,通过源码分析、解释它是如何实现扩展的原理,包括一些 golang 程序设计技巧。



七、References