From bbd054511f3b0bc9aba0f3eca5707dac581ad1e6 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Thu, 29 Aug 2019 16:42:18 +0800
Subject: [PATCH 01/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 7f9b248..496d6a7 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# 压测工具如何选择? ab、locust、Jmeter、go压测工具【单台机器100w连接压测实战】
+# go实现的压测工具【单台机器100w连接压测实战】
本文介绍压测是什么,解释压测的专属名词,教大家如何压测。介绍市面上的常见压测工具(ab、locust、Jmeter、go实现的压测工具、云压测),对比这些压测工具,教大家如何选择一款适合自己的压测工具,本文还有两个压测实战项目:
@@ -21,7 +21,7 @@
- [3、常见的压测工具](#3常见的压测工具)
- [3.1 ab](#31-ab)
- [3.2 locust](#32-locust)
- - [3.3 Jmeter](#33-Jmeter)
+ - [3.3 JMeter](#33-JMeter)
- [3.4 云压测](#34-云压测)
- [3.4.1 云压测介绍](#341-云压测介绍)
- [3.4.2 阿里云 性能测试 PTS](#342-阿里云-性能测试-PTS)
@@ -387,7 +387,7 @@ Hatch rate (users spawned/second) 每秒钟增加用户数

-### 3.3 Jmeter
+### 3.3 JMeter
- 简介
From 9e05c774d16b7ef21e659c07a8a4792072c60816 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Fri, 30 Aug 2019 14:09:18 +0800
Subject: [PATCH 02/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 496d6a7..f570cf4 100644
--- a/README.md
+++ b/README.md
@@ -701,7 +701,7 @@ centOS 7.6 上述设置不生效,需要手动修改配置文件
core 是限制内核文件的大小,这里设置为 unlimited
```
-# 添加一下参数
+# 添加以下参数
root soft nofile 1040000
root hard nofile 1040000
From 191394f019fd9c9b211474050256a07cceaa0187 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Fri, 30 Aug 2019 14:14:14 +0800
Subject: [PATCH 03/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index f570cf4..6f10711 100644
--- a/README.md
+++ b/README.md
@@ -755,6 +755,8 @@ net.ipv4.tcp_rmem = 4096 4096 16777216
net.ipv4.tcp_wmem = 4096 4096 16777216
```
+`sysctl -p` 修改配置以后使得配置生效命令
+
配置解释:
- `ip_local_port_range` 表示TCP/UDP协议允许使用的本地端口号 范围:1024~65000
From 4221dbe1d43b0e4a48551e3a61adb07e8123a012 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Sat, 31 Aug 2019 14:20:25 +0800
Subject: [PATCH 04/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index 6f10711..10636e5 100644
--- a/README.md
+++ b/README.md
@@ -63,7 +63,7 @@ go 实现的压测工具,每个用户用一个协程的方式模拟,最大
`-u` 需要压测的地址
-```shell script
+```shell
# clone 项目
git clone https://github.com/link1st/go-stress-testing.git
@@ -196,10 +196,10 @@ go run main.go -c 1 -n 100 -u https://www.baidu.com/
- 机器: 峰值时间每秒钟请求数(QPS) / 单台机器的QPS = 需要的机器的数量
- 假设:网站每天的用户数(100W),每天的用户的访问量约为3000W PV,这台机器的需要多少QPS?
-> `( 30000000*0.8 ) / (86400 * 0.2) ≈ 1389 (QPS)`
+> ( 30000000\*0.8 ) / (86400 * 0.2) ≈ 1389 (QPS)
- 假设:单台机器的的QPS是69,需要需要多少台机器来支撑?
-> `1389 / 69 ≈ 20`
+> 1389 / 69 ≈ 20
## 3、常见的压测工具
### 3.1 ab
@@ -211,7 +211,7 @@ ab属于一个轻量级的压测工具,结果不会特别准确,可以用作
- 安装
-```shell script
+```shell
# 在linux环境安装
sudo yum -y install httpd
```
@@ -232,7 +232,7 @@ Options are:
- 压测命令
-```shell script
+```shell
# 使用ab压测工具,对百度的链接 请求100次,并发数1
ab -n 100 -c 1 https://www.baidu.com/
```
@@ -311,7 +311,7 @@ Percentage of the requests served within a certain time (ms)
- 安装
-```shell script
+```shell
# pip3 安装locust
pip3 install locust
# 查看是否安装成功
@@ -345,7 +345,7 @@ class WebsiteUser(HttpLocust):
- 启动压测
-```shell script
+```shell
locust -f test.py --host=https://www.baidu.com
```
From 1b60b3815c0fc76f889713363f36463c2a28fcbd Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Sun, 1 Sep 2019 14:03:37 +0800
Subject: [PATCH 05/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/README.md b/README.md
index 10636e5..969742b 100644
--- a/README.md
+++ b/README.md
@@ -44,8 +44,6 @@
- [8、参考文献](#8参考文献)
-
-
## 1、项目说明
### 1.1 go-stress-testing
From bad241fd45d56bd5cefa90b7378100a1458d8c78 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Tue, 10 Sep 2019 19:29:31 +0800
Subject: [PATCH 06/75] add GitHub actions
---
.github/workflows/release.yml | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
create mode 100644 .github/workflows/release.yml
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..bf654d5
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,25 @@
+name: Release
+on:
+ create:
+ tags:
+ - v*
+jobs:
+
+ release:
+ name: Release on GitHub
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out chode
+ uses: actions/checkout@v1
+
+ - name: Validates GO releaser config
+ uses: docker://goreleaser/goreleaser:latest
+ with:
+ args: check
+
+ - name: Create release on GitHub
+ uses: docker://goreleaser/goreleaser:latest
+ with:
+ args: release
+ env:
+ GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
\ No newline at end of file
From f2cbb1a3ca93386f3b585d42bc5b19447ba3885f Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Tue, 10 Sep 2019 19:43:18 +0800
Subject: [PATCH 07/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/workflows/release.yml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index bf654d5..c3d18f1 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -12,6 +12,9 @@ jobs:
- name: Check out chode
uses: actions/checkout@v1
+ - name: Go PATH
+ run: export PATH=$PATH:$(go env GOPATH)/bin
+
- name: Validates GO releaser config
uses: docker://goreleaser/goreleaser:latest
with:
From cd6bc19a6f71dec6ea4f47cd6816dbef20308911 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Tue, 10 Sep 2019 19:47:12 +0800
Subject: [PATCH 08/75] gitHub actions
---
.github/workflows/release.yml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index c3d18f1..ed99a06 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -12,14 +12,14 @@ jobs:
- name: Check out chode
uses: actions/checkout@v1
- - name: Go PATH
- run: export PATH=$PATH:$(go env GOPATH)/bin
-
- name: Validates GO releaser config
uses: docker://goreleaser/goreleaser:latest
with:
args: check
+ - name: Go PATH
+ run: export PATH=$PATH:$(go env GOPATH)/bin
+
- name: Create release on GitHub
uses: docker://goreleaser/goreleaser:latest
with:
From fd598df371cce1912237144286eaa831de77eda1 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 11 Sep 2019 14:03:25 +0800
Subject: [PATCH 09/75] gitHub actions
---
.github/workflows/release.yml | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ed99a06..cb73e23 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -17,6 +17,18 @@ jobs:
with:
args: check
+#/home/runner/work/actions/actions
+ - name: go path
+ run: |
+ ls
+ cd ..
+ pwd
+ mkdir -vp go/{src/,bin/,pkg/}
+ mv go-stress-testing go/src/
+ export GOPATH=${pwd}/go
+ export GO111MODULE=off
+ cd go/src/go-stress-testing
+
- name: Go PATH
run: export PATH=$PATH:$(go env GOPATH)/bin
From c8276dce84b74a208fde3028fc3f216821a0d40e Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 11 Sep 2019 14:04:54 +0800
Subject: [PATCH 10/75] gitHub actions
---
.github/workflows/push.yml | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 .github/workflows/push.yml
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
new file mode 100644
index 0000000..f753ab5
--- /dev/null
+++ b/.github/workflows/push.yml
@@ -0,0 +1,36 @@
+name: Go actions
+on:
+ push:
+ branches:
+ - master
+jobs:
+
+ build:
+ name: Build
+ runs-on: ubuntu-latest
+ steps:
+
+ - name: Set up Go 1.12
+ uses: actions/setup-go@v1
+ with:
+ go-version: 1.12
+ id: go
+
+ - name: Check out code into the Go module directory
+ uses: actions/checkout@v1
+
+ - name: Get dependencies
+ run: |
+ go get -v -t -d ./...
+ if [ -f Gopkg.toml ]; then
+ curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
+ dep ensure
+ fi
+
+ - name: ls
+ run: |
+ ls
+ pwd
+
+ - name: run
+ run: go run main.go -c 1 -n 100 -u https://www.baidu.com/
\ No newline at end of file
From ac5562df1adb94923b7229c948bc65da930518ec Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 11 Sep 2019 14:09:31 +0800
Subject: [PATCH 11/75] actions
---
.github/workflows/push.yml | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index f753ab5..53af1fd 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -19,6 +19,21 @@ jobs:
- name: Check out code into the Go module directory
uses: actions/checkout@v1
+ #/home/runner/work/actions
+ - name: go path
+ run: |
+ ls
+ cd ..
+ pwd
+ mkdir -vp go/{src/,bin/,pkg/}
+ mv go-stress-testing go/src/
+ export GOPATH=${pwd}/go
+ export GO111MODULE=off
+ cd go/src/go-stress-testing
+
+ - name: Go PATH
+ run: export PATH=$PATH:$(go env GOPATH)/bin
+
- name: Get dependencies
run: |
go get -v -t -d ./...
From bd026e7fd2389ff7760e280f0a65c09c00a21b80 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 11 Sep 2019 14:16:15 +0800
Subject: [PATCH 12/75] actions
---
.github/workflows/push.yml | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index 53af1fd..102541c 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -27,9 +27,13 @@ jobs:
pwd
mkdir -vp go/{src/,bin/,pkg/}
mv go-stress-testing go/src/
- export GOPATH=${pwd}/go
+ export GOPATH=${pwd}/go/
export GO111MODULE=off
cd go/src/go-stress-testing
+ ls
+ go env
+ echo $(go env GOPATH)
+
- name: Go PATH
run: export PATH=$PATH:$(go env GOPATH)/bin
From ddba9f8833ba18746bdb09473d147293b4e415ae Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 11 Sep 2019 14:20:06 +0800
Subject: [PATCH 13/75] actions
---
.github/workflows/push.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index 102541c..3e229b7 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -27,7 +27,7 @@ jobs:
pwd
mkdir -vp go/{src/,bin/,pkg/}
mv go-stress-testing go/src/
- export GOPATH=${pwd}/go/
+ export GOPATH=$(pwd)/go/
export GO111MODULE=off
cd go/src/go-stress-testing
ls
From d500e97e35a0f10e76f6483b2172b127a75eee30 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 11 Sep 2019 14:24:49 +0800
Subject: [PATCH 14/75] actions
---
.github/workflows/push.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index 3e229b7..011a30b 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -25,11 +25,13 @@ jobs:
ls
cd ..
pwd
+ ls
mkdir -vp go/{src/,bin/,pkg/}
mv go-stress-testing go/src/
export GOPATH=$(pwd)/go/
export GO111MODULE=off
cd go/src/go-stress-testing
+ pwd
ls
go env
echo $(go env GOPATH)
From d9b561fb2b65bacd28020ec626d2b977e628d956 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 11 Sep 2019 14:29:27 +0800
Subject: [PATCH 15/75] actions
---
.github/workflows/push.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index 011a30b..5c0f500 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -35,6 +35,7 @@ jobs:
ls
go env
echo $(go env GOPATH)
+ ls $(go env GOPATH)
- name: Go PATH
From 79f1cfb66a5b39479069bfd9b56160b3c5b864a3 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 11 Sep 2019 14:32:46 +0800
Subject: [PATCH 16/75] actions
---
.github/workflows/push.yml | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index 5c0f500..b92befc 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -36,10 +36,12 @@ jobs:
go env
echo $(go env GOPATH)
ls $(go env GOPATH)
+ echo $(go env GOPATH)/bin/
+ ls $(go env GOPATH)/bin/
- - name: Go PATH
- run: export PATH=$PATH:$(go env GOPATH)/bin
+# - name: Go PATH
+# run: export PATH=$PATH:$(go env GOPATH)/bin/
- name: Get dependencies
run: |
From 046fcaee4fac034ead657402d5e9be49aca4a53f Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 11 Sep 2019 14:36:35 +0800
Subject: [PATCH 17/75] actions
---
.github/workflows/push.yml | 19 +++----------------
1 file changed, 3 insertions(+), 16 deletions(-)
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index b92befc..388ef5b 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -28,28 +28,15 @@ jobs:
ls
mkdir -vp go/{src/,bin/,pkg/}
mv go-stress-testing go/src/
- export GOPATH=$(pwd)/go/
+ export GOPATH=$(pwd)/go
export GO111MODULE=off
cd go/src/go-stress-testing
pwd
- ls
- go env
- echo $(go env GOPATH)
- ls $(go env GOPATH)
echo $(go env GOPATH)/bin/
- ls $(go env GOPATH)/bin/
-
-# - name: Go PATH
-# run: export PATH=$PATH:$(go env GOPATH)/bin/
- - name: Get dependencies
- run: |
- go get -v -t -d ./...
- if [ -f Gopkg.toml ]; then
- curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
- dep ensure
- fi
+ - name: Go PATH
+ run: export PATH=$PATH:$(go env GOPATH)/bin/
- name: ls
run: |
From 01cfbedb842eeebc17d0afd3f768b1a65cec34a0 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 11 Sep 2019 14:38:49 +0800
Subject: [PATCH 18/75] actions
---
.github/workflows/push.yml | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index 388ef5b..42d9a22 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -34,9 +34,8 @@ jobs:
pwd
echo $(go env GOPATH)/bin/
-
- - name: Go PATH
- run: export PATH=$PATH:$(go env GOPATH)/bin/
+# - name: Go PATH
+# run: export PATH=$PATH:$(go env GOPATH)/bin/
- name: ls
run: |
From 886468eb0ef684ac126a72afe3d96b4335f11ee6 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 11 Sep 2019 14:44:33 +0800
Subject: [PATCH 19/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/workflows/push.yml | 46 -----------------------------------
.github/workflows/release.yml | 40 ------------------------------
.gitignore | 3 ++-
README.md | 3 +++
4 files changed, 5 insertions(+), 87 deletions(-)
delete mode 100644 .github/workflows/push.yml
delete mode 100644 .github/workflows/release.yml
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
deleted file mode 100644
index 42d9a22..0000000
--- a/.github/workflows/push.yml
+++ /dev/null
@@ -1,46 +0,0 @@
-name: Go actions
-on:
- push:
- branches:
- - master
-jobs:
-
- build:
- name: Build
- runs-on: ubuntu-latest
- steps:
-
- - name: Set up Go 1.12
- uses: actions/setup-go@v1
- with:
- go-version: 1.12
- id: go
-
- - name: Check out code into the Go module directory
- uses: actions/checkout@v1
-
- #/home/runner/work/actions
- - name: go path
- run: |
- ls
- cd ..
- pwd
- ls
- mkdir -vp go/{src/,bin/,pkg/}
- mv go-stress-testing go/src/
- export GOPATH=$(pwd)/go
- export GO111MODULE=off
- cd go/src/go-stress-testing
- pwd
- echo $(go env GOPATH)/bin/
-
-# - name: Go PATH
-# run: export PATH=$PATH:$(go env GOPATH)/bin/
-
- - name: ls
- run: |
- ls
- pwd
-
- - name: run
- run: go run main.go -c 1 -n 100 -u https://www.baidu.com/
\ No newline at end of file
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
deleted file mode 100644
index cb73e23..0000000
--- a/.github/workflows/release.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-name: Release
-on:
- create:
- tags:
- - v*
-jobs:
-
- release:
- name: Release on GitHub
- runs-on: ubuntu-latest
- steps:
- - name: Check out chode
- uses: actions/checkout@v1
-
- - name: Validates GO releaser config
- uses: docker://goreleaser/goreleaser:latest
- with:
- args: check
-
-#/home/runner/work/actions/actions
- - name: go path
- run: |
- ls
- cd ..
- pwd
- mkdir -vp go/{src/,bin/,pkg/}
- mv go-stress-testing go/src/
- export GOPATH=${pwd}/go
- export GO111MODULE=off
- cd go/src/go-stress-testing
-
- - name: Go PATH
- run: export PATH=$PATH:$(go env GOPATH)/bin
-
- - name: Create release on GitHub
- uses: docker://goreleaser/goreleaser:latest
- with:
- args: release
- env:
- GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 66b3677..d3148ed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,4 +18,5 @@ go_stress_testing_mac
go_stress_testing_linux
go_stress_testing_win.exe
curl.txt
-*curl.txt
\ No newline at end of file
+*curl.txt
+go-stress-testing-mac
\ No newline at end of file
diff --git a/README.md b/README.md
index 969742b..7403f57 100644
--- a/README.md
+++ b/README.md
@@ -53,6 +53,8 @@ go 实现的压测工具,每个用户用一个协程的方式模拟,最大
- 可以在 mac/linux/windows 不同平台下执行的命令
+- [go-stress-testing][https://github.com/link1st/go-stress-testing/releases] 下载地址
+
参数说明:
`-c` 表示并发数
@@ -439,6 +441,7 @@ PTS(Performance Testing Service)是面向所有技术背景人员的云化
### 4.2 用法
+- [go-stress-testing][https://github.com/link1st/go-stress-testing/releases] 下载地址
- 支持参数:
```
From 4a05ecf3aa650a9dad4ece6d9178acb3f9316377 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 11 Sep 2019 15:01:49 +0800
Subject: [PATCH 20/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 9 ++++-----
README.md | 27 +++++++++++----------------
build.sh | 6 +++---
3 files changed, 18 insertions(+), 24 deletions(-)
diff --git a/.gitignore b/.gitignore
index d3148ed..946e4c5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,9 +14,8 @@
main
main_linux
main_win.exe
-go_stress_testing_mac
-go_stress_testing_linux
-go_stress_testing_win.exe
+go-stress-testing-mac
+go-stress-testing-linux
+go-stress-testing-win.exe
curl.txt
-*curl.txt
-go-stress-testing-mac
\ No newline at end of file
+*curl.txt
\ No newline at end of file
diff --git a/README.md b/README.md
index 7403f57..4c4e204 100644
--- a/README.md
+++ b/README.md
@@ -53,7 +53,7 @@ go 实现的压测工具,每个用户用一个协程的方式模拟,最大
- 可以在 mac/linux/windows 不同平台下执行的命令
-- [go-stress-testing][https://github.com/link1st/go-stress-testing/releases] 下载地址
+- [go-stress-testing](https://github.com/link1st/go-stress-testing/releases) 压测工具下载地址
参数说明:
@@ -65,15 +65,8 @@ go 实现的压测工具,每个用户用一个协程的方式模拟,最大
```shell
-# clone 项目
-git clone https://github.com/link1st/go-stress-testing.git
-
-# 进入项目目录
-cd go-stress-testing
-
-# 运行
-go run main.go -c 1 -n 100 -u https://www.baidu.com/
-
+# 运行 以mac为示例
+./go-stress-testing-mac -c 1 -n 100 -u https://www.baidu.com/
```
@@ -462,27 +455,29 @@ Usage of ./go_stress_testing_mac:
- `-n` 是单个用户请求的次数,请求总次数 = `-c`* `-n`, 这里考虑的是模拟用户行为,所以这个是每个用户请求的次数
+- [下载地址](https://github.com/link1st/go-stress-testing/releases)
+
+- 下载以后执行下面命令即可压测
- 使用示例:
```
# 查看用法
-go run main.go
+./go-stress-testing-mac
# 使用请求百度页面
-go run main.go -c 1 -n 100 -u https://www.baidu.com/
+./go-stress-testing-mac -c 1 -n 100 -u https://www.baidu.com/
# 使用debug模式请求百度页面
-go run main.go -c 1 -n 1 -d true -u https://www.baidu.com/
+./go-stress-testing-mac -c 1 -n 1 -d true -u https://www.baidu.com/
# 使用 curl文件(文件在curl目录下) 的方式请求
-go run main.go -c 1 -n 1 -p curl/baidu.curl.txt
+./go-stress-testing-mac -c 1 -n 1 -p curl/baidu.curl.txt
# 压测webSocket连接
-go run main.go -c 10 -n 10 -u ws://127.0.0.1:8089/acc
+./go-stress-testing-mac -c 10 -n 10 -u ws://127.0.0.1:8089/acc
```
-
- 使用 curl文件进行压测
curl是Linux在命令行下的工作的文件传输工具,是一款很强大的http命令行工具。
diff --git a/build.sh b/build.sh
index 822276c..818dd21 100755
--- a/build.sh
+++ b/build.sh
@@ -1,8 +1,8 @@
#!/usr/bin/env bash
# 编译mac下可以执行文件
-go build -o go_stress_testing_mac main.go
+go build -o go-stress-testing-mac main.go
# 使用交叉编译 linux和windows版本可以执行的文件
-CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o go_stress_testing_linux main.go
-CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o go_stress_testing_win.exe main.go
+CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o go-stress-testing-linux main.go
+CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o go-stress-testing-win.exe main.go
From a2d0db479a7f9f7d003e0c5b9c312cf56ed7afe6 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 11 Sep 2019 15:05:48 +0800
Subject: [PATCH 21/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 4c4e204..6e2cc79 100644
--- a/README.md
+++ b/README.md
@@ -434,11 +434,11 @@ PTS(Performance Testing Service)是面向所有技术背景人员的云化
### 4.2 用法
-- [go-stress-testing][https://github.com/link1st/go-stress-testing/releases] 下载地址
+- [go-stress-testing](https://github.com/link1st/go-stress-testing/releases) 下载地址
- 支持参数:
```
-Usage of ./go_stress_testing_mac:
+Usage of ./go-stress-testing-mac:
-c uint
并发数 (default 1)
-d string
@@ -455,8 +455,6 @@ Usage of ./go_stress_testing_mac:
- `-n` 是单个用户请求的次数,请求总次数 = `-c`* `-n`, 这里考虑的是模拟用户行为,所以这个是每个用户请求的次数
-- [下载地址](https://github.com/link1st/go-stress-testing/releases)
-
- 下载以后执行下面命令即可压测
- 使用示例:
From 9ecc1f19f67d623cee70f25f4ca96e9d78dd2d31 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Fri, 21 Feb 2020 11:58:22 +0800
Subject: [PATCH 22/75] fix io.Reader bug
---
model/curl_model.go | 19 +++----------------
model/curl_model_test.go | 2 +-
model/request_model.go | 10 ++++++++--
server/golink/http_link.go | 2 +-
4 files changed, 13 insertions(+), 20 deletions(-)
diff --git a/model/curl_model.go b/model/curl_model.go
index 191c4bd..368c2e8 100644
--- a/model/curl_model.go
+++ b/model/curl_model.go
@@ -10,7 +10,6 @@ package model
import (
"encoding/json"
"errors"
- "io"
"io/ioutil"
"os"
"strings"
@@ -172,7 +171,7 @@ func (c *CURL) GetHeadersStr() string {
}
// 获取body
-func (c *CURL) GetBody() (body io.Reader) {
+func (c *CURL) GetBody() (body string) {
value, ok := c.Data["--data"]
if !ok {
@@ -189,20 +188,8 @@ func (c *CURL) GetBody() (body io.Reader) {
return
}
- body = strings.NewReader(value[0])
+ // body = strings.NewReader(value[0])
+ body = value[0]
return
}
-
-// 获取body
-func (c *CURL) GetBodyStr() (str string) {
-
- body := c.GetBody()
- if body == nil {
-
- return
- }
- bytes, _ := ioutil.ReadAll(body)
- str = string(bytes)
- return
-}
diff --git a/model/curl_model_test.go b/model/curl_model_test.go
index dbf7ec4..ef6a7aa 100644
--- a/model/curl_model_test.go
+++ b/model/curl_model_test.go
@@ -25,7 +25,7 @@ func TestCurl(t *testing.T) {
fmt.Printf("url:%s \n", c.GetUrl())
fmt.Printf("method:%s \n", c.GetMethod())
fmt.Printf("body:%v \n", c.GetBody())
- fmt.Printf("body string:%v \n", c.GetBodyStr())
+ fmt.Printf("body string:%v \n", c.GetBody())
fmt.Printf("headers:%s \n", c.GetHeadersStr())
diff --git a/model/request_model.go b/model/request_model.go
index 35e479d..f2809f1 100644
--- a/model/request_model.go
+++ b/model/request_model.go
@@ -70,7 +70,7 @@ type Request struct {
Form string // http/webSocket/tcp
Method string // 方法 get/post/put
Headers map[string]string // Headers
- Body io.Reader // body
+ Body string // body
Verify string // 验证的方法
VerifyHttp VerifyHttp // 验证的方法
VerifyWebSocket VerifyWebSocket // 验证的方法
@@ -81,6 +81,12 @@ type Request struct {
// 循环事件 切片 时间 动作
}
+func (r *Request) GetBody() (body io.Reader) {
+ body = strings.NewReader(r.Body)
+
+ return
+}
+
// NewRequest
// url 压测的url
// verify 验证方法 在server/verify中 http 支持:statusCode、json webSocket支持:json
@@ -92,7 +98,7 @@ func NewRequest(url string, verify string, timeout time.Duration, debug bool, pa
var (
method = "GET"
headers = make(map[string]string)
- body io.Reader
+ body string
)
if path != "" {
diff --git a/server/golink/http_link.go b/server/golink/http_link.go
index 1d70292..4b7f223 100644
--- a/server/golink/http_link.go
+++ b/server/golink/http_link.go
@@ -31,7 +31,7 @@ func Http(chanId uint64, ch chan<- *model.RequestResults, totalNumber uint64, wg
errCode = model.HttpOk
)
- resp, err := client.HttpRequest(request.Method, request.Url, request.Body, request.Headers, request.Timeout)
+ resp, err := client.HttpRequest(request.Method, request.Url, request.GetBody(), request.Headers, request.Timeout)
requestTime := uint64(heper.DiffNano(startTime))
// resp, err := server.HttpGetResp(request.Url)
if err != nil {
From dc01d61ec325201a8b38ba8f273da971c8b7a7f4 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 6 May 2020 15:42:03 +0800
Subject: [PATCH 23/75] =?UTF-8?q?fix=20postman=20curl=E6=96=87=E4=BB=B6?=
=?UTF-8?q?=E8=A7=A3=E6=9E=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 4 +-
curl/test.chrome.curl.copy.txt | 11 +++
curl/test.curl.txt | 11 +++
curl/test.postman.curl.copy.txt | 4 +
model/curl_model.go | 138 +++++++++++++++++++++-----------
model/request_model.go | 6 +-
6 files changed, 126 insertions(+), 48 deletions(-)
create mode 100644 curl/test.chrome.curl.copy.txt
create mode 100644 curl/test.curl.txt
create mode 100644 curl/test.postman.curl.copy.txt
diff --git a/.gitignore b/.gitignore
index 946e4c5..ca38fc5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,5 +17,5 @@ main_win.exe
go-stress-testing-mac
go-stress-testing-linux
go-stress-testing-win.exe
-curl.txt
-*curl.txt
\ No newline at end of file
+model/modeltest/*
+model/modeltest*
\ No newline at end of file
diff --git a/curl/test.chrome.curl.copy.txt b/curl/test.chrome.curl.copy.txt
new file mode 100644
index 0000000..9f53972
--- /dev/null
+++ b/curl/test.chrome.curl.copy.txt
@@ -0,0 +1,11 @@
+curl 'https://www.baidu.com/sugrec?prod=pc_his&from=pc_web&json=1&sid=1464_21098_31424_31341_31464_31229_30823_31163_31475&hisdata=&req=2&csor=0' \
+ -H 'Connection: keep-alive' \
+ -H 'Accept: application/json, text/javascript, */*; q=0.01' \
+ -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36' \
+ -H 'Sec-Fetch-Site: same-origin' \
+ -H 'Sec-Fetch-Mode: cors' \
+ -H 'Sec-Fetch-Dest: empty' \
+ -H 'Referer: https://www.baidu.com/' \
+ -H 'Accept-Language: zh-CN,zh;q=0.9' \
+ -H 'Cookie: BIDUPSID=A2CDAA36D74F85E5007CAA415E35B9DF; PSTM=1588732560; BAIDUID=A2CDAA36D74F85E59E4B8060EC4A0230:FG=1; BD_HOME=1; BD_UPN=123253; H_PS_PSSID=1464_21098_31424_31341_31464_31229_30823_31163_31475' \
+ --compressed
\ No newline at end of file
diff --git a/curl/test.curl.txt b/curl/test.curl.txt
new file mode 100644
index 0000000..9f53972
--- /dev/null
+++ b/curl/test.curl.txt
@@ -0,0 +1,11 @@
+curl 'https://www.baidu.com/sugrec?prod=pc_his&from=pc_web&json=1&sid=1464_21098_31424_31341_31464_31229_30823_31163_31475&hisdata=&req=2&csor=0' \
+ -H 'Connection: keep-alive' \
+ -H 'Accept: application/json, text/javascript, */*; q=0.01' \
+ -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36' \
+ -H 'Sec-Fetch-Site: same-origin' \
+ -H 'Sec-Fetch-Mode: cors' \
+ -H 'Sec-Fetch-Dest: empty' \
+ -H 'Referer: https://www.baidu.com/' \
+ -H 'Accept-Language: zh-CN,zh;q=0.9' \
+ -H 'Cookie: BIDUPSID=A2CDAA36D74F85E5007CAA415E35B9DF; PSTM=1588732560; BAIDUID=A2CDAA36D74F85E59E4B8060EC4A0230:FG=1; BD_HOME=1; BD_UPN=123253; H_PS_PSSID=1464_21098_31424_31341_31464_31229_30823_31163_31475' \
+ --compressed
\ No newline at end of file
diff --git a/curl/test.postman.curl.copy.txt b/curl/test.postman.curl.copy.txt
new file mode 100644
index 0000000..ad81434
--- /dev/null
+++ b/curl/test.postman.curl.copy.txt
@@ -0,0 +1,4 @@
+curl -X GET \
+ 'https://www.baidu.com/sugrec?prod=pc_his&from=pc_web&json=1&sid=1464_21098_31424_31341_31464_31229_30823_31163_31475&hisdata=&req=2&csor=0' \
+ -H 'Postman-Token: c9b71950-61fd-43be-a38a-6596de238f0f' \
+ -H 'cache-control: no-cache'
\ No newline at end of file
diff --git a/model/curl_model.go b/model/curl_model.go
index 368c2e8..3bec701 100644
--- a/model/curl_model.go
+++ b/model/curl_model.go
@@ -20,6 +20,25 @@ type CURL struct {
Data map[string][]string
}
+func (c *CURL) getDataValue(keys []string) []string {
+ var (
+ value = make([]string, 0)
+ )
+
+ for _, key := range keys {
+ var (
+ ok bool
+ )
+
+ value, ok = c.Data[key]
+ if ok {
+ break
+ }
+ }
+
+ return value
+}
+
// 从文件中解析curl
func ParseTheFile(path string) (curl *CURL, err error) {
@@ -44,39 +63,88 @@ func ParseTheFile(path string) (curl *CURL, err error) {
file.Close()
}()
- data, err := ioutil.ReadAll(file)
+ dataBytes, err := ioutil.ReadAll(file)
if err != nil {
err = errors.New("读取文件失败:" + err.Error())
return
}
+ data := string(dataBytes)
+
+ for len(data) > 0 {
+ if strings.HasPrefix(data, "curl") {
+ data = data[5:]
+ }
+
+ data = strings.TrimSpace(data)
+ var (
+ key string
+ value string
+ )
- dataStr := string(data)
- for true {
- index := strings.Index(dataStr, "'")
+ index := strings.Index(data, " ")
if index <= 0 {
break
}
+ key = strings.TrimSpace(data[:index])
+ data = data[index+1:]
+ data = strings.TrimSpace(data)
+
+ // url
+ if !strings.HasPrefix(key, "-") {
+ key = strings.Trim(key, "'")
+ curl.Data["curl"] = []string{key}
+
+ // 去除首尾空格
+ data = strings.TrimFunc(data, func(r rune) bool {
+ if r == ' ' || r == '\\' || r == '\n' {
+ return true
+ }
+
+ return false
+ })
+ continue
+ }
- key := strings.TrimSpace(dataStr[:index])
- key = strings.ReplaceAll(key, "\n", "")
+ if strings.HasPrefix(data, "-") {
+ continue
+ }
- dataStr = dataStr[index+1:]
+ var (
+ endSymbol = " "
+ )
- index = strings.Index(dataStr, "'")
+ if strings.HasPrefix(data, "'") {
+ endSymbol = "'"
+ data = data[1:]
+ }
- if index <= 0 {
+ index = strings.Index(data, endSymbol)
+ if index <= -1 {
break
}
+ value = data[:index]
+ data = data[index+1:]
- value := dataStr[:index]
+ // 去除首尾空格
+ data = strings.TrimFunc(data, func(r rune) bool {
+ if r == ' ' || r == '\\' || r == '\n' {
+ return true
+ }
- dataStr = dataStr[index+1:]
+ return false
+ })
curl.Data[key] = append(curl.Data[key], value)
+ // break
+
}
+ // for key, value := range curl.Data {
+ // fmt.Println("key:", key, "value:", value)
+ // }
+
return
}
@@ -88,12 +156,9 @@ func (c *CURL) String() (url string) {
// GetUrl
func (c *CURL) GetUrl() (url string) {
- value, ok := c.Data["curl"]
- if !ok {
-
- return
- }
+ keys := []string{"curl"}
+ value := c.getDataValue(keys)
if len(value) <= 0 {
return
@@ -108,24 +173,17 @@ func (c *CURL) GetUrl() (url string) {
func (c *CURL) GetMethod() (method string) {
method = "GET"
- if _, ok := c.Data["--data"]; ok {
- method = "POST"
+ var (
+ postKeys = []string{"--d", "--data", "--data-binary $", "--data-binary"}
+ )
+ value := c.getDataValue(postKeys)
- return
+ if len(value) >= 1 {
+ return "POST"
}
- // TODO::目前发送不了
- if _, ok := c.Data["--data-binary $"]; ok {
- method = "POST"
-
- return
- }
-
- value, ok := c.Data["-X"]
- if !ok {
-
- return
- }
+ keys := []string{"-X", "--request"}
+ value = c.getDataValue(keys)
if len(value) <= 0 {
@@ -141,11 +199,8 @@ func (c *CURL) GetMethod() (method string) {
func (c *CURL) GetHeaders() (headers map[string]string) {
headers = make(map[string]string, 0)
- value, ok := c.Data["-H"]
- if !ok {
-
- return
- }
+ keys := []string{"-H", "--header"}
+ value := c.getDataValue(keys)
for _, v := range value {
index := strings.Index(v, ":")
@@ -173,15 +228,8 @@ func (c *CURL) GetHeadersStr() string {
// 获取body
func (c *CURL) GetBody() (body string) {
- value, ok := c.Data["--data"]
- if !ok {
- // data-binary
- value, ok = c.Data["--data-binary $"]
- if !ok {
-
- return
- }
- }
+ keys := []string{"--data", "-d", "--data-raw", "--data-binary"}
+ value := c.getDataValue(keys)
if len(value) <= 0 {
diff --git a/model/request_model.go b/model/request_model.go
index f2809f1..2469454 100644
--- a/model/request_model.go
+++ b/model/request_model.go
@@ -122,6 +122,9 @@ func NewRequest(url string, verify string, timeout time.Duration, debug bool, pa
form = FormTypeHttp
} else if strings.HasPrefix(url, "ws://") || strings.HasPrefix(url, "wss://") {
form = FormTypeWebSocket
+ } else {
+ form = FormTypeHttp
+ url = fmt.Sprintf("http://%s", url)
}
if form == "" {
@@ -194,7 +197,8 @@ func (r *Request) Print() {
return
}
- result := fmt.Sprintf("request:\n url:%s \n form:%s \n method:%s \n headers:%v \n", r.Url, r.Form, r.Method, r.Headers)
+ result := fmt.Sprintf("request:\n form:%s \n url:%s \n method:%s \n headers:%v \n", r.Form, r.Url, r.Method, r.Headers)
+ result = fmt.Sprintf("%s data:%v \n", result, r.Body)
result = fmt.Sprintf("%s verify:%s \n timeout:%s \n debu:%v \n", result, r.Verify, r.Timeout, r.Debug)
fmt.Println(result)
From 38e554e9c6ddeb014a2daaf026f2613d28b6dea7 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 6 May 2020 17:44:23 +0800
Subject: [PATCH 24/75] add test
---
...t.chrome.curl.copy.txt => test.chrome.curl.txt} | 0
curl/test.post.cur.txt | 14 ++++++++++++++
...postman.curl.copy.txt => test.postman.curl.txt} | 0
3 files changed, 14 insertions(+)
rename curl/{test.chrome.curl.copy.txt => test.chrome.curl.txt} (100%)
create mode 100644 curl/test.post.cur.txt
rename curl/{test.postman.curl.copy.txt => test.postman.curl.txt} (100%)
diff --git a/curl/test.chrome.curl.copy.txt b/curl/test.chrome.curl.txt
similarity index 100%
rename from curl/test.chrome.curl.copy.txt
rename to curl/test.chrome.curl.txt
diff --git a/curl/test.post.cur.txt b/curl/test.post.cur.txt
new file mode 100644
index 0000000..63f8c3b
--- /dev/null
+++ b/curl/test.post.cur.txt
@@ -0,0 +1,14 @@
+curl 'https://page.aliyun.com/delivery/plan/list' \
+ -H 'authority: page.aliyun.com' \
+ -H 'accept: application/json, text/plain, */*' \
+ -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36' \
+ -H 'content-type: application/x-www-form-urlencoded' \
+ -H 'origin: https://cn.aliyun.com' \
+ -H 'sec-fetch-site: same-site' \
+ -H 'sec-fetch-mode: cors' \
+ -H 'sec-fetch-dest: empty' \
+ -H 'referer: https://cn.aliyun.com/' \
+ -H 'accept-language: zh-CN,zh;q=0.9' \
+ -H 'cookie: aliyun_choice=CN; JSESSIONID=J8866281-CKCFJ4BUZ7GDO9V89YBW1-KJ3J5V9K-GYUW7; maliyun_temporary_console0=1AbLByOMHeZe3G41KYd5WWZvrM%2BGErkaLcWfBbgveKA9ifboArprPASvFUUfhwHtt44qsDwVqMk8Wkdr1F5LccYk2mPCZJiXb0q%2Bllj5u3SQGQurtyPqnG489y%2FkoA%2FEvOwsXJTvXTFQPK%2BGJD4FJg%3D%3D; cna=L3Q5F8cHDGgCAXL3r8fEZtdU; isg=BFNThsmSCcgX-sUcc5Jo2s2T4tF9COfKYi8g9wVwr3KphHMmjdh3GrHFvPTqJD_C; l=eBaceXLnQGBjstRJBOfwPurza77OSIRAguPzaNbMiT5POw1B5WAlWZbqyNY6C3GVh6lwR37EODnaBeYBc3K-nxvOu9eFfGMmn' \
+ --data 'adPlanQueryParam=%7B%22adZone%22%3A%7B%22positionList%22%3A%5B%7B%22positionId%22%3A83%7D%5D%7D%2C%22requestId%22%3A%2217958651-f205-44c7-ad5d-f8af92a6217a%22%7D' \
+ --compressed
\ No newline at end of file
diff --git a/curl/test.postman.curl.copy.txt b/curl/test.postman.curl.txt
similarity index 100%
rename from curl/test.postman.curl.copy.txt
rename to curl/test.postman.curl.txt
From b211ce675611713b21565cdc1f25cad0277192f1 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 6 May 2020 17:55:08 +0800
Subject: [PATCH 25/75] update timeout
---
model/request_model.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/model/request_model.go b/model/request_model.go
index 2469454..9f6091d 100644
--- a/model/request_model.go
+++ b/model/request_model.go
@@ -170,7 +170,7 @@ func NewRequest(url string, verify string, timeout time.Duration, debug bool, pa
}
if timeout == 0 {
- timeout = 3 * time.Second
+ timeout = 30 * time.Second
}
request = &Request{
From 7a18fa9a0df6f5ffa59cc61604e6035c8660cb5f Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Mon, 18 May 2020 11:15:21 +0800
Subject: [PATCH 26/75] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=91=BD=E4=BB=A4?=
=?UTF-8?q?=E8=A1=8C=20header=E3=80=81body=20=E5=8F=82=E6=95=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 17 +++++++++++++++++
main.go | 18 +++++++++++++++++-
model/curl_model.go | 5 +++--
model/request_model.go | 21 ++++++++++++++++++++-
4 files changed, 57 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 6e2cc79..f03f473 100644
--- a/README.md
+++ b/README.md
@@ -476,6 +476,23 @@ Usage of ./go-stress-testing-mac:
./go-stress-testing-mac -c 10 -n 10 -u ws://127.0.0.1:8089/acc
```
+- 完整压测命令示例
+```shell script
+# 更多参数 支持 header、post body
+go run main.go -c 1 -n 1 -d true -u 'https://page.aliyun.com/delivery/plan/list' \
+ -H 'authority: page.aliyun.com' \
+ -H 'accept: application/json, text/plain, */*' \
+ -H 'content-type: application/x-www-form-urlencoded' \
+ -H 'origin: https://cn.aliyun.com' \
+ -H 'sec-fetch-site: same-site' \
+ -H 'sec-fetch-mode: cors' \
+ -H 'sec-fetch-dest: empty' \
+ -H 'referer: https://cn.aliyun.com/' \
+ -H 'accept-language: zh-CN,zh;q=0.9' \
+ -H 'cookie: aliyun_choice=CN; JSESSIONID=J8866281-CKCFJ4BUZ7GDO9V89YBW1-KJ3J5V9K-GYUW7; maliyun_temporary_console0=1AbLByOMHeZe3G41KYd5WWZvrM%2BGErkaLcWfBbgveKA9ifboArprPASvFUUfhwHtt44qsDwVqMk8Wkdr1F5LccYk2mPCZJiXb0q%2Bllj5u3SQGQurtyPqnG489y%2FkoA%2FEvOwsXJTvXTFQPK%2BGJD4FJg%3D%3D; cna=L3Q5F8cHDGgCAXL3r8fEZtdU; isg=BFNThsmSCcgX-sUcc5Jo2s2T4tF9COfKYi8g9wVwr3KphHMmjdh3GrHFvPTqJD_C; l=eBaceXLnQGBjstRJBOfwPurza77OSIRAguPzaNbMiT5POw1B5WAlWZbqyNY6C3GVh6lwR37EODnaBeYBc3K-nxvOu9eFfGMmn' \
+ -data 'adPlanQueryParam=%7B%22adZone%22%3A%7B%22positionList%22%3A%5B%7B%22positionId%22%3A83%7D%5D%7D%2C%22requestId%22%3A%2217958651-f205-44c7-ad5d-f8af92a6217a%22%7D'
+```
+
- 使用 curl文件进行压测
curl是Linux在命令行下的工作的文件传输工具,是一款很强大的http命令行工具。
diff --git a/main.go b/main.go
index 3fc9e4a..6c30b99 100644
--- a/main.go
+++ b/main.go
@@ -16,6 +16,18 @@ import (
"strings"
)
+type array []string
+
+func (a *array) String() string {
+ return fmt.Sprint(*a)
+}
+
+func (a *array) Set(s string) error {
+ *a = append(*a, s)
+
+ return nil
+}
+
// go 实现的压测工具
//
// 编译可执行文件
@@ -31,6 +43,8 @@ func main() {
requestUrl string // 压测的url 目前支持,http/https ws/wss
path string // curl文件路径 http接口压测,自定义参数设置
verify string // verify 验证方法 在server/verify中 http 支持:statusCode、json webSocket支持:json
+ headers array // 自定义头信息传递给服务器
+ body string // HTTP POST方式传送数据
)
flag.Uint64Var(&concurrency, "c", 1, "并发数")
@@ -39,6 +53,8 @@ func main() {
flag.StringVar(&requestUrl, "u", "", "压测地址")
flag.StringVar(&path, "p", "", "curl文件路径")
flag.StringVar(&verify, "v", "", "验证方法 http 支持:statusCode、json webSocket支持:json")
+ flag.Var(&headers, "H", "自定义头信息传递给服务器 示例:-header 'Content-Type: application/json'")
+ flag.StringVar(&body, "data", "", "HTTP POST方式传送数据")
// 解析参数
flag.Parse()
@@ -53,7 +69,7 @@ func main() {
}
debug := strings.ToLower(debugStr) == "true"
- request, err := model.NewRequest(requestUrl, verify, 0, debug, path)
+ request, err := model.NewRequest(requestUrl, verify, 0, debug, path, headers, body)
if err != nil {
fmt.Printf("参数不合法 %v \n", err)
diff --git a/model/curl_model.go b/model/curl_model.go
index 3bec701..56fbf7b 100644
--- a/model/curl_model.go
+++ b/model/curl_model.go
@@ -208,9 +208,10 @@ func (c *CURL) GetHeaders() (headers map[string]string) {
continue
}
- vIndex := index + 2
+ vIndex := index + 1
if len(v) >= vIndex {
- headers[v[:index]] = v[vIndex:]
+ value := v[vIndex:]
+ headers[v[:index]] = strings.TrimPrefix(value, " ")
}
}
diff --git a/model/request_model.go b/model/request_model.go
index 9f6091d..b29068d 100644
--- a/model/request_model.go
+++ b/model/request_model.go
@@ -93,7 +93,7 @@ func (r *Request) GetBody() (body io.Reader) {
// timeout 请求超时时间
// debug 是否开启debug
// path curl文件路径 http接口压测,自定义参数设置
-func NewRequest(url string, verify string, timeout time.Duration, debug bool, path string) (request *Request, err error) {
+func NewRequest(url string, verify string, timeout time.Duration, debug bool, path string, reqHeaders []string, reqBody string) (request *Request, err error) {
var (
method = "GET"
@@ -115,6 +115,25 @@ func NewRequest(url string, verify string, timeout time.Duration, debug bool, pa
method = curl.GetMethod()
headers = curl.GetHeaders()
body = curl.GetBody()
+ } else {
+
+ if reqBody != "" {
+ method = "POST"
+ body = reqBody
+ }
+
+ for _, v := range reqHeaders {
+ index := strings.Index(v, ":")
+ if index < 0 {
+ continue
+ }
+
+ vIndex := index + 1
+ if len(v) >= vIndex {
+ value := v[vIndex:]
+ headers[v[:index]] = strings.TrimPrefix(value, " ")
+ }
+ }
}
form := ""
From 166953ca4f1db6b3565d80c5bd17e1d4f889a097 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Mon, 18 May 2020 14:00:39 +0800
Subject: [PATCH 27/75] fix
---
model/curl_model.go | 11 +----------
model/request_model.go | 31 +++++++++++++++++++++----------
2 files changed, 22 insertions(+), 20 deletions(-)
diff --git a/model/curl_model.go b/model/curl_model.go
index 56fbf7b..0f1a041 100644
--- a/model/curl_model.go
+++ b/model/curl_model.go
@@ -203,16 +203,7 @@ func (c *CURL) GetHeaders() (headers map[string]string) {
value := c.getDataValue(keys)
for _, v := range value {
- index := strings.Index(v, ":")
- if index < 0 {
- continue
- }
-
- vIndex := index + 1
- if len(v) >= vIndex {
- value := v[vIndex:]
- headers[v[:index]] = strings.TrimPrefix(value, " ")
- }
+ getHeaderValue(v, headers)
}
return
diff --git a/model/request_model.go b/model/request_model.go
index b29068d..7670c0a 100644
--- a/model/request_model.go
+++ b/model/request_model.go
@@ -120,19 +120,12 @@ func NewRequest(url string, verify string, timeout time.Duration, debug bool, pa
if reqBody != "" {
method = "POST"
body = reqBody
+
+ headers["Content-Type"] = "application/x-www-form-urlencoded; charset=utf-8"
}
for _, v := range reqHeaders {
- index := strings.Index(v, ":")
- if index < 0 {
- continue
- }
-
- vIndex := index + 1
- if len(v) >= vIndex {
- value := v[vIndex:]
- headers[v[:index]] = strings.TrimPrefix(value, " ")
- }
+ getHeaderValue(v, headers)
}
}
@@ -209,6 +202,24 @@ func NewRequest(url string, verify string, timeout time.Duration, debug bool, pa
}
+func getHeaderValue(v string, headers map[string]string) {
+ index := strings.Index(v, ":")
+ if index < 0 {
+ return
+ }
+
+ vIndex := index + 1
+ if len(v) >= vIndex {
+ value := strings.TrimPrefix(v[vIndex:], " ")
+
+ if _, ok := headers[v[:index]]; ok {
+ headers[v[:index]] = fmt.Sprintf("%s; %s", headers[v[:index]], value)
+ } else {
+ headers[v[:index]] = value
+ }
+ }
+}
+
// 打印
func (r *Request) Print() {
if r == nil {
From 3a96307b99a88f69ef955af18849430c3439d72c Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 20 May 2020 18:31:56 +0800
Subject: [PATCH 28/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index f03f473..15e595a 100644
--- a/README.md
+++ b/README.md
@@ -40,8 +40,9 @@
- [6.3 客户端配置](#63-客户端配置)
- [6.4 准备](#64-准备)
- [6.5 压测数据](#65-压测数据)
-- [7、总结](#7总结)
-- [8、参考文献](#8参考文献)
+- [7、常见问题](#7常见问题)
+- [8、总结](#8总结)
+- [9、参考文献](#9参考文献)
## 1、项目说明
@@ -849,7 +850,17 @@ VmSize: 27133804 kB
至此,压测已经全部完成,单台机器支持100W连接已经满足~
-## 7、总结
+## 7.常见问题
+- **Q:** 压测过程中服务器出现大量 **TIME_WAIT**
+
+ A: 参考TCP四次挥手原理,主动关闭连接的一方会出现 **TIME_WAIT** 状态,等待的时长为 2MSL(约1分钟左右)
+
+ 原因是:主动断开的一方回复 ACK 消息可能丢失,TCP 是可靠的传输协议,在没有收到 ACK 消息的另一端会重试,重新发送FIN消息,所以主动关闭的一方会等待 2MSL 时间,防止对方重试,这就出现了大量 **TIME_WAIT** 状态(参考: 四次挥手的最后两次)
+
+TCP 握手:
+
+
+## 8、总结
到这里压测总算完成,本次压测花费16元巨款。
@@ -858,7 +869,7 @@ VmSize: 27133804 kB
本文通过介绍什么是压测,在什么情况下需要压测,通过单台机器100W长连接的压测实战了解Linux内核的参数的调优。如果觉得现有的压测工具不适用,可以自己实现或者是改造成属于自己的自己的工具。
-## 8、参考文献
+## 9、参考文献
[性能测试工具](https://testerhome.com/topics/17068)
From af5077b999b8eeadf0ab357a155b9d722b177e01 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 20 May 2020 18:32:37 +0800
Subject: [PATCH 29/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 15e595a..a004f02 100644
--- a/README.md
+++ b/README.md
@@ -851,7 +851,7 @@ VmSize: 27133804 kB
至此,压测已经全部完成,单台机器支持100W连接已经满足~
## 7.常见问题
-- **Q:** 压测过程中服务器出现大量 **TIME_WAIT**
+- **Q:** 压测过程中会出现大量 **TIME_WAIT**
A: 参考TCP四次挥手原理,主动关闭连接的一方会出现 **TIME_WAIT** 状态,等待的时长为 2MSL(约1分钟左右)
From a8ab10d978d8eeca23ed533f31c94eeac2ff130c Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 20 May 2020 18:36:17 +0800
Subject: [PATCH 30/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index a004f02..09e5c70 100644
--- a/README.md
+++ b/README.md
@@ -858,7 +858,7 @@ VmSize: 27133804 kB
原因是:主动断开的一方回复 ACK 消息可能丢失,TCP 是可靠的传输协议,在没有收到 ACK 消息的另一端会重试,重新发送FIN消息,所以主动关闭的一方会等待 2MSL 时间,防止对方重试,这就出现了大量 **TIME_WAIT** 状态(参考: 四次挥手的最后两次)
TCP 握手:
-
+
## 8、总结
From f56182c6c18a71242585c83b8d2f7488a4dbf6fa Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 3 Jun 2020 20:34:12 +0800
Subject: [PATCH 31/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index 09e5c70..bf664bb 100644
--- a/README.md
+++ b/README.md
@@ -429,7 +429,7 @@ PTS(Performance Testing Service)是面向所有技术背景人员的云化
### 4.1 介绍
-- go-stress-testing 是go语言实现的简单压测工具,源码开源、支持二次开发,可以压测http、webSocket请求,使用协程模拟单个用户,可以更高效的利用CPU资源。
+- go-stress-testing 是go语言实现的简单压测工具,源码开源、支持二次开发,可以压测http、webSocket请求、私有rpc调用,使用协程模拟单个用户,可以更高效的利用CPU资源。
- 项目地址 [https://github.com/link1st/go-stress-testing](https://github.com/link1st/go-stress-testing)
@@ -441,17 +441,21 @@ PTS(Performance Testing Service)是面向所有技术背景人员的云化
```
Usage of ./go-stress-testing-mac:
-c uint
- 并发数 (default 1)
+ 并发数 (default 1)
-d string
- 调试模式 (default "false")
+ 调试模式 (default "false")
+ -data string
+ HTTP POST方式传送数据
-n uint
- 请求总数 (default 1)
+ 请求总数 (default 1)
-p string
- curl文件路径
+ curl文件路径
-u string
- 请求地址
+ 压测地址
-v string
- 验证方法 http 支持:statusCode、json webSocket支持:json (default "statusCode")
+ 验证方法 http 支持:statusCode、json webSocket支持:json
+ -H value
+ 自定义头信息传递给服务器 示例:-header 'Content-Type: application/json'
```
- `-n` 是单个用户请求的次数,请求总次数 = `-c`* `-n`, 这里考虑的是模拟用户行为,所以这个是每个用户请求的次数
From 8699eb4556c5b62e593ced49bb505fa5299792bb Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 3 Jun 2020 20:47:04 +0800
Subject: [PATCH 32/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index bf664bb..acc26d4 100644
--- a/README.md
+++ b/README.md
@@ -505,8 +505,12 @@ curl是Linux在命令行下的工作的文件传输工具,是一款很强大
使用curl文件可以压测使用非GET的请求,支持设置http请求的 method、cookies、header、body等参数
-chrome 浏览器生成 curl文件,打开开发者模式(快捷键F12),如图所示,生成 curl 在终端执行命令
-
+**I**: chrome 浏览器生成 curl文件,打开开发者模式(快捷键F12),如图所示,生成 curl 在终端执行命令
+
+
+**II** postman 生成 curl 命令
+
+
生成内容粘贴到项目目录下的**curl/baidu.curl.txt**文件中,执行下面命令就可以从curl.txt文件中读取需要压测的内容进行压测了
From d97e33e118af3b77c551416a024453d8274783f3 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Wed, 3 Jun 2020 21:38:44 +0800
Subject: [PATCH 33/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 27 ++++++++++++---------------
1 file changed, 12 insertions(+), 15 deletions(-)
diff --git a/README.md b/README.md
index acc26d4..fa8e58a 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,8 @@
本文介绍压测是什么,解释压测的专属名词,教大家如何压测。介绍市面上的常见压测工具(ab、locust、Jmeter、go实现的压测工具、云压测),对比这些压测工具,教大家如何选择一款适合自己的压测工具,本文还有两个压测实战项目:
-- 单台机器对HTTP短连接 QPS 1W+ 的压测实战
-- 单台机器100W长连接的压测实战
+- 单台机器对 HTTP 短连接 QPS 1W+ 的压测实战
+- 单台机器 100W 长连接的压测实战
## 目录
- [1、项目说明](#1项目说明)
@@ -48,7 +48,7 @@
## 1、项目说明
### 1.1 go-stress-testing
-go 实现的压测工具,每个用户用一个协程的方式模拟,最大限度的利用CPU资源
+go 实现的压测工具,每个用户用一个协程的方式模拟,最大限度的利用 CPU 资源
### 1.2 项目体验
@@ -60,7 +60,7 @@ go 实现的压测工具,每个用户用一个协程的方式模拟,最大
`-c` 表示并发数
-`-n` 每个并发执行请求的次数,总请求的次数 = 并发数 * 每个并发执行请求的次数
+`-n` 每个并发执行请求的次数,总请求的次数 = 并发数 `*` 每个并发执行请求的次数
`-u` 需要压测的地址
@@ -125,7 +125,6 @@ go 实现的压测工具,每个用户用一个协程的方式模拟,最大
**错误码**: 压测中,接口返回的 code码:返回次数的集合
-
## 2、压测
### 2.1 压测是什么
@@ -138,7 +137,6 @@ go 实现的压测工具,每个用户用一个协程的方式模拟,最大
- 压测的目的就是通过压测(模拟真实用户的行为),测算出机器的性能(单台机器的QPS),从而推算出系统在承受指定用户数(100W)时,需要多少机器能支撑得住
- 压测是在上线前为了应对未来可能达到的用户数量的一次预估(提前演练),压测以后通过优化程序的性能或准备充足的机器,来保证用户的体验。
-
### 2.3 压测名词解释
#### 2.3.1 压测类型解释
@@ -183,10 +181,10 @@ go 实现的压测工具,每个用户用一个协程的方式模拟,最大
### 2.4 如何计算压测指标
-- 压测我们需要有目的性的压测,这次压测我们需要达到什么目标(如:单台机器的性能为100QPS?网站能同时满足100W人同时在线)
+- 压测我们需要有目的性的压测,这次压测我们需要达到什么目标(如:单台机器的性能为 100QPS?网站能同时满足100W人同时在线)
- 可以通过以下计算方法来进行计算:
- 压测原则:每天80%的访问量集中在20%的时间里,这20%的时间就叫做峰值
-- 公式: ( 总PV数*80% ) / ( 每天的秒数*20% ) = 峰值时间每秒钟请求数(QPS)
+- 公式: ( 总PV数`*`80% ) / ( 每天的秒数`*`20% ) = 峰值时间每秒钟请求数(QPS)
- 机器: 峰值时间每秒钟请求数(QPS) / 单台机器的QPS = 需要的机器的数量
- 假设:网站每天的用户数(100W),每天的用户的访问量约为3000W PV,这台机器的需要多少QPS?
@@ -199,9 +197,9 @@ go 实现的压测工具,每个用户用一个协程的方式模拟,最大
### 3.1 ab
- 简介
-ApacheBench 是 Apache服务器自带的一个web压力测试工具,简称ab。ab又是一个命令行工具,对发起负载的本机要求很低,根据ab命令可以创建很多的并发访问线程,模拟多个访问者同时对某一URL地址进行访问,因此可以用来测试目标服务器的负载压力。总的来说ab工具小巧简单,上手学习较快,可以提供需要的基本性能指标,但是没有图形化结果,不能监控。
+ApacheBench 是 Apache 服务器自带的一个web压力测试工具,简称 ab。ab 又是一个命令行工具,对发起负载的本机要求很低,根据 ab 命令可以创建很多的并发访问线程,模拟多个访问者同时对某一 URL 地址进行访问,因此可以用来测试目标服务器的负载压力。总的来说 ab 工具小巧简单,上手学习较快,可以提供需要的基本性能指标,但是没有图形化结果,不能监控。
-ab属于一个轻量级的压测工具,结果不会特别准确,可以用作参考。
+ab 属于一个轻量级的压测工具,结果不会特别准确,可以用作参考。
- 安装
@@ -291,7 +289,7 @@ Percentage of the requests served within a certain time (ms)
- `Failed requests` 失败个数
-- `Requests per second` 吞吐量,指的是某个并发用户下单位时间内处理的请求数。等效于QPS,其实可以看作同一个统计方式,只是叫法不同而已。
+- `Requests per second` 吞吐量,指的是某个并发用户下单位时间内处理的请求数。等效于 QPS,其实可以看作同一个统计方式,只是叫法不同而已。
- `Time per request` 用户平均请求等待时间
@@ -301,7 +299,7 @@ Percentage of the requests served within a certain time (ms)
- 简介
-是非常简单易用、分布式、python开发的压力测试工具。有图形化界面,支持将压测数据导出。
+是非常简单易用、分布式、python 开发的压力测试工具。有图形化界面,支持将压测数据导出。
- 安装
@@ -505,13 +503,12 @@ curl是Linux在命令行下的工作的文件传输工具,是一款很强大
使用curl文件可以压测使用非GET的请求,支持设置http请求的 method、cookies、header、body等参数
-**I**: chrome 浏览器生成 curl文件,打开开发者模式(快捷键F12),如图所示,生成 curl 在终端执行命令
+**I:** chrome 浏览器生成 curl文件,打开开发者模式(快捷键F12),如图所示,生成 curl 在终端执行命令

-**II** postman 生成 curl 命令
+**II:** postman 生成 curl 命令

-
生成内容粘贴到项目目录下的**curl/baidu.curl.txt**文件中,执行下面命令就可以从curl.txt文件中读取需要压测的内容进行压测了
```
From a973f4ad4a24d7363b937c99fd99fbd15fb6854d Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Tue, 9 Jun 2020 14:22:16 +0800
Subject: [PATCH 34/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index fa8e58a..4f26437 100644
--- a/README.md
+++ b/README.md
@@ -434,6 +434,7 @@ PTS(Performance Testing Service)是面向所有技术背景人员的云化
### 4.2 用法
- [go-stress-testing](https://github.com/link1st/go-stress-testing/releases) 下载地址
+- clone 项目源码运行的时候,需要将项目 clone 到 **$GOPATH** 目录下
- 支持参数:
```
From 3f325bf9040c35320445d08e04bfbf3472212540 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Thu, 18 Jun 2020 12:56:35 +0800
Subject: [PATCH 35/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 4f26437..d291141 100644
--- a/README.md
+++ b/README.md
@@ -573,6 +573,7 @@ package main
import (
"log"
"net/http"
+ "runtime"
)
const (
From 11dcf09991083ecae7144167069d1f40855e48e0 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Thu, 18 Jun 2020 13:00:14 +0800
Subject: [PATCH 36/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index d291141..639e3b4 100644
--- a/README.md
+++ b/README.md
@@ -585,7 +585,7 @@ func main() {
runtime.GOMAXPROCS(runtime.NumCPU() - 1)
hello := func(w http.ResponseWriter, req *http.Request) {
- data := "Hello, World!"
+ data := "Hello, go-stress-testing! \n"
w.Header().Add("Server", "golang")
w.Write([]byte(data))
From 83916d9881d20cc3eb543a82879b4874af2dd83f Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Thu, 18 Jun 2020 13:15:20 +0800
Subject: [PATCH 37/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/README.md b/README.md
index 639e3b4..a15225e 100644
--- a/README.md
+++ b/README.md
@@ -897,3 +897,12 @@ TCP 握手:
[https://github.com/link1st/go-stress-testing](https://github.com/link1st/go-stress-testing)
github 搜:link1st 查看项目 go-stress-testing
+
+### 意见反馈
+
+- 在项目中遇到问题可以直接在这里找找答案或者提问 [issues](https://github.com/link1st/go-stress-testing/issues)
+- 也可以添加我的微信(申请信息填写:公司、姓名,我好备注下),直接反馈给我
+
+
+
+
From 339e1477b388fc244a4ac8a505ae97407e3fb1c2 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Thu, 18 Jun 2020 16:38:33 +0800
Subject: [PATCH 38/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 8 ++++----
model/request_model.go | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index a15225e..44d067e 100644
--- a/README.md
+++ b/README.md
@@ -159,9 +159,9 @@ go 实现的压测工具,每个用户用一个协程的方式模拟,最大
| 请求成功数(Request Success Number) | 在一次压测中,请求成功的数量 |
| 请求失败数(Request Failures Number) | 在一次压测中,请求失败的数量 |
| 错误率(Error Rate) | 在压测中,请求成功的数量与请求失败数量的比率 |
-| 最大响应时间(Max Response Time) | 在一次事务中,从发出请求或指令系统做出的反映(响应)的最大时间 |
-| 最少响应时间(Mininum Response Time) | 在一次事务中,从发出请求或指令系统做出的反映(响应)的最少时间 |
-| 平均响应时间(Average Response Time) | 在一次事务中,从发出请求或指令系统做出的反映(响应)的平均时间 |
+| 最大响应时间(Max Response Time) | 在一次压测中,从发出请求或指令系统做出的反映(响应)的最大时间 |
+| 最少响应时间(Mininum Response Time) | 在一次压测中,从发出请求或指令系统做出的反映(响应)的最少时间 |
+| 平均响应时间(Average Response Time) | 在一次压测中,从发出请求或指令系统做出的反映(响应)的平均时间 |
#### 2.3.3 机器性能指标解释
@@ -606,7 +606,7 @@ func main() {
- go_stress_testing 压测命令
```
-./go_stress_testing_linux -c 100 -n 10000 -u http://127.0.0.1:8088/
+./go-stress-testing-linux -c 100 -n 10000 -u http://127.0.0.1:8088/
```
diff --git a/model/request_model.go b/model/request_model.go
index 7670c0a..e9b6fa6 100644
--- a/model/request_model.go
+++ b/model/request_model.go
@@ -229,7 +229,7 @@ func (r *Request) Print() {
result := fmt.Sprintf("request:\n form:%s \n url:%s \n method:%s \n headers:%v \n", r.Form, r.Url, r.Method, r.Headers)
result = fmt.Sprintf("%s data:%v \n", result, r.Body)
- result = fmt.Sprintf("%s verify:%s \n timeout:%s \n debu:%v \n", result, r.Verify, r.Timeout, r.Debug)
+ result = fmt.Sprintf("%s verify:%s \n timeout:%s \n debug:%v \n", result, r.Verify, r.Timeout, r.Debug)
fmt.Println(result)
return
From 8dc8f2707a9b581be78d6152bc19dfa23f68614d Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Thu, 18 Jun 2020 17:53:41 +0800
Subject: [PATCH 39/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
main.go | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 44d067e..bdbafab 100644
--- a/README.md
+++ b/README.md
@@ -454,7 +454,7 @@ Usage of ./go-stress-testing-mac:
-v string
验证方法 http 支持:statusCode、json webSocket支持:json
-H value
- 自定义头信息传递给服务器 示例:-header 'Content-Type: application/json'
+ 自定义头信息传递给服务器 示例:-H 'Content-Type: application/json'
```
- `-n` 是单个用户请求的次数,请求总次数 = `-c`* `-n`, 这里考虑的是模拟用户行为,所以这个是每个用户请求的次数
diff --git a/main.go b/main.go
index 6c30b99..9854d3f 100644
--- a/main.go
+++ b/main.go
@@ -53,7 +53,7 @@ func main() {
flag.StringVar(&requestUrl, "u", "", "压测地址")
flag.StringVar(&path, "p", "", "curl文件路径")
flag.StringVar(&verify, "v", "", "验证方法 http 支持:statusCode、json webSocket支持:json")
- flag.Var(&headers, "H", "自定义头信息传递给服务器 示例:-header 'Content-Type: application/json'")
+ flag.Var(&headers, "H", "自定义头信息传递给服务器 示例:-H 'Content-Type: application/json'")
flag.StringVar(&body, "data", "", "HTTP POST方式传送数据")
// 解析参数
From 93d18ec071dad730206c2971db1d30c326f553a4 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Fri, 19 Jun 2020 09:52:49 +0800
Subject: [PATCH 40/75] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8F=90=E7=A4=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 16 ++++++++--------
main.go | 4 ++--
server/statistics/statistics.go | 2 +-
3 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index bdbafab..de4c22e 100644
--- a/README.md
+++ b/README.md
@@ -441,20 +441,20 @@ PTS(Performance Testing Service)是面向所有技术背景人员的云化
Usage of ./go-stress-testing-mac:
-c uint
并发数 (default 1)
+ -n uint
+ 请求数(单个并发/协程) (default 1)
+ -u string
+ 压测地址
-d string
调试模式 (default "false")
+ -H value
+ 自定义头信息传递给服务器 示例:-H 'Content-Type: application/json'
-data string
HTTP POST方式传送数据
- -n uint
- 请求总数 (default 1)
- -p string
- curl文件路径
- -u string
- 压测地址
-v string
验证方法 http 支持:statusCode、json webSocket支持:json
- -H value
- 自定义头信息传递给服务器 示例:-H 'Content-Type: application/json'
+ -p string
+ curl文件路径
```
- `-n` 是单个用户请求的次数,请求总次数 = `-c`* `-n`, 这里考虑的是模拟用户行为,所以这个是每个用户请求的次数
diff --git a/main.go b/main.go
index 9854d3f..3e14d83 100644
--- a/main.go
+++ b/main.go
@@ -38,7 +38,7 @@ func main() {
var (
concurrency uint64 // 并发数
- totalNumber uint64 // 请求总数(单个并发)
+ totalNumber uint64 // 请求数(单个并发/协程)
debugStr string // 是否是debug
requestUrl string // 压测的url 目前支持,http/https ws/wss
path string // curl文件路径 http接口压测,自定义参数设置
@@ -48,7 +48,7 @@ func main() {
)
flag.Uint64Var(&concurrency, "c", 1, "并发数")
- flag.Uint64Var(&totalNumber, "n", 1, "请求总数")
+ flag.Uint64Var(&totalNumber, "n", 1, "请求数(单个并发/协程)")
flag.StringVar(&debugStr, "d", "false", "调试模式")
flag.StringVar(&requestUrl, "u", "", "压测地址")
flag.StringVar(&path, "p", "", "curl文件路径")
diff --git a/server/statistics/statistics.go b/server/statistics/statistics.go
index 00b5ed7..efaaf3a 100644
--- a/server/statistics/statistics.go
+++ b/server/statistics/statistics.go
@@ -116,7 +116,7 @@ func ReceivingResults(concurrent uint64, ch <-chan *model.RequestResults, wg *sy
fmt.Println("************************* 结果 stat ****************************")
fmt.Println("处理协程数量:", concurrent)
// fmt.Println("处理协程数量:", concurrent, "程序处理总时长:", fmt.Sprintf("%.3f", float64(processingTime/concurrent)/1e9), "秒")
- fmt.Println("请求总数:", successNum+failureNum, "总请求时间:", fmt.Sprintf("%.3f", float64(requestTime)/1e9),
+ fmt.Println("请求总数(并发数*请求数 -c * -n):", successNum+failureNum, "总请求时间:", fmt.Sprintf("%.3f", float64(requestTime)/1e9),
"秒", "successNum:", successNum, "failureNum:", failureNum)
fmt.Println("************************* 结果 end ****************************")
From 5bdc17f95f2046bf91464ff5db8c9739269aeb5a Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Mon, 22 Jun 2020 16:54:46 +0800
Subject: [PATCH 41/75] =?UTF-8?q?=E6=94=AF=E6=8C=81=20curl=20--url=20?=
=?UTF-8?q?=E5=8F=82=E6=95=B0=20=E8=AE=BE=E7=BD=AEurl?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
model/curl_model.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/model/curl_model.go b/model/curl_model.go
index 0f1a041..8a8bc12 100644
--- a/model/curl_model.go
+++ b/model/curl_model.go
@@ -157,7 +157,7 @@ func (c *CURL) String() (url string) {
// GetUrl
func (c *CURL) GetUrl() (url string) {
- keys := []string{"curl"}
+ keys := []string{"curl","--url"}
value := c.getDataValue(keys)
if len(value) <= 0 {
From 2eaf3861c9e01bce9c5b3ce4071bcc712709e3cc Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Sun, 28 Jun 2020 10:56:22 +0800
Subject: [PATCH 42/75] =?UTF-8?q?=E8=BF=81=E7=A7=BB=20go=20mod?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
go.mod | 5 +
go.sum | 5 +
vendor/golang.org/x/net/LICENSE | 27 -
vendor/golang.org/x/net/PATENTS | 22 -
vendor/golang.org/x/net/websocket/client.go | 106 ----
vendor/golang.org/x/net/websocket/dial.go | 24 -
vendor/golang.org/x/net/websocket/hybi.go | 583 ------------------
vendor/golang.org/x/net/websocket/server.go | 113 ----
.../golang.org/x/net/websocket/websocket.go | 451 --------------
vendor/vendor.json | 14 -
10 files changed, 10 insertions(+), 1340 deletions(-)
create mode 100644 go.mod
create mode 100644 go.sum
delete mode 100644 vendor/golang.org/x/net/LICENSE
delete mode 100644 vendor/golang.org/x/net/PATENTS
delete mode 100644 vendor/golang.org/x/net/websocket/client.go
delete mode 100644 vendor/golang.org/x/net/websocket/dial.go
delete mode 100644 vendor/golang.org/x/net/websocket/hybi.go
delete mode 100644 vendor/golang.org/x/net/websocket/server.go
delete mode 100644 vendor/golang.org/x/net/websocket/websocket.go
delete mode 100644 vendor/vendor.json
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..d9021ef
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,5 @@
+module go-stress-testing
+
+go 1.14
+
+require golang.org/x/net v0.0.0-20190724013045-ca1201d0de80
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..c037375
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,5 @@
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/vendor/golang.org/x/net/LICENSE b/vendor/golang.org/x/net/LICENSE
deleted file mode 100644
index 6a66aea..0000000
--- a/vendor/golang.org/x/net/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2009 The Go Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/golang.org/x/net/PATENTS b/vendor/golang.org/x/net/PATENTS
deleted file mode 100644
index 7330990..0000000
--- a/vendor/golang.org/x/net/PATENTS
+++ /dev/null
@@ -1,22 +0,0 @@
-Additional IP Rights Grant (Patents)
-
-"This implementation" means the copyrightable works distributed by
-Google as part of the Go project.
-
-Google hereby grants to You a perpetual, worldwide, non-exclusive,
-no-charge, royalty-free, irrevocable (except as stated in this section)
-patent license to make, have made, use, offer to sell, sell, import,
-transfer and otherwise run, modify and propagate the contents of this
-implementation of Go, where such license applies only to those patent
-claims, both currently owned or controlled by Google and acquired in
-the future, licensable by Google that are necessarily infringed by this
-implementation of Go. This grant does not include claims that would be
-infringed only as a consequence of further modification of this
-implementation. If you or your agent or exclusive licensee institute or
-order or agree to the institution of patent litigation against any
-entity (including a cross-claim or counterclaim in a lawsuit) alleging
-that this implementation of Go or any code incorporated within this
-implementation of Go constitutes direct or contributory patent
-infringement, or inducement of patent infringement, then any patent
-rights granted to you under this License for this implementation of Go
-shall terminate as of the date such litigation is filed.
diff --git a/vendor/golang.org/x/net/websocket/client.go b/vendor/golang.org/x/net/websocket/client.go
deleted file mode 100644
index 69a4ac7..0000000
--- a/vendor/golang.org/x/net/websocket/client.go
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "bufio"
- "io"
- "net"
- "net/http"
- "net/url"
-)
-
-// DialError is an error that occurs while dialling a websocket server.
-type DialError struct {
- *Config
- Err error
-}
-
-func (e *DialError) Error() string {
- return "websocket.Dial " + e.Config.Location.String() + ": " + e.Err.Error()
-}
-
-// NewConfig creates a new WebSocket config for client connection.
-func NewConfig(server, origin string) (config *Config, err error) {
- config = new(Config)
- config.Version = ProtocolVersionHybi13
- config.Location, err = url.ParseRequestURI(server)
- if err != nil {
- return
- }
- config.Origin, err = url.ParseRequestURI(origin)
- if err != nil {
- return
- }
- config.Header = http.Header(make(map[string][]string))
- return
-}
-
-// NewClient creates a new WebSocket client connection over rwc.
-func NewClient(config *Config, rwc io.ReadWriteCloser) (ws *Conn, err error) {
- br := bufio.NewReader(rwc)
- bw := bufio.NewWriter(rwc)
- err = hybiClientHandshake(config, br, bw)
- if err != nil {
- return
- }
- buf := bufio.NewReadWriter(br, bw)
- ws = newHybiClientConn(config, buf, rwc)
- return
-}
-
-// Dial opens a new client connection to a WebSocket.
-func Dial(url_, protocol, origin string) (ws *Conn, err error) {
- config, err := NewConfig(url_, origin)
- if err != nil {
- return nil, err
- }
- if protocol != "" {
- config.Protocol = []string{protocol}
- }
- return DialConfig(config)
-}
-
-var portMap = map[string]string{
- "ws": "80",
- "wss": "443",
-}
-
-func parseAuthority(location *url.URL) string {
- if _, ok := portMap[location.Scheme]; ok {
- if _, _, err := net.SplitHostPort(location.Host); err != nil {
- return net.JoinHostPort(location.Host, portMap[location.Scheme])
- }
- }
- return location.Host
-}
-
-// DialConfig opens a new client connection to a WebSocket with a config.
-func DialConfig(config *Config) (ws *Conn, err error) {
- var client net.Conn
- if config.Location == nil {
- return nil, &DialError{config, ErrBadWebSocketLocation}
- }
- if config.Origin == nil {
- return nil, &DialError{config, ErrBadWebSocketOrigin}
- }
- dialer := config.Dialer
- if dialer == nil {
- dialer = &net.Dialer{}
- }
- client, err = dialWithDialer(dialer, config)
- if err != nil {
- goto Error
- }
- ws, err = NewClient(config, client)
- if err != nil {
- client.Close()
- goto Error
- }
- return
-
-Error:
- return nil, &DialError{config, err}
-}
diff --git a/vendor/golang.org/x/net/websocket/dial.go b/vendor/golang.org/x/net/websocket/dial.go
deleted file mode 100644
index 2dab943..0000000
--- a/vendor/golang.org/x/net/websocket/dial.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "crypto/tls"
- "net"
-)
-
-func dialWithDialer(dialer *net.Dialer, config *Config) (conn net.Conn, err error) {
- switch config.Location.Scheme {
- case "ws":
- conn, err = dialer.Dial("tcp", parseAuthority(config.Location))
-
- case "wss":
- conn, err = tls.DialWithDialer(dialer, "tcp", parseAuthority(config.Location), config.TlsConfig)
-
- default:
- err = ErrBadScheme
- }
- return
-}
diff --git a/vendor/golang.org/x/net/websocket/hybi.go b/vendor/golang.org/x/net/websocket/hybi.go
deleted file mode 100644
index 8cffdd1..0000000
--- a/vendor/golang.org/x/net/websocket/hybi.go
+++ /dev/null
@@ -1,583 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-// This file implements a protocol of hybi draft.
-// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17
-
-import (
- "bufio"
- "bytes"
- "crypto/rand"
- "crypto/sha1"
- "encoding/base64"
- "encoding/binary"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "net/url"
- "strings"
-)
-
-const (
- websocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
-
- closeStatusNormal = 1000
- closeStatusGoingAway = 1001
- closeStatusProtocolError = 1002
- closeStatusUnsupportedData = 1003
- closeStatusFrameTooLarge = 1004
- closeStatusNoStatusRcvd = 1005
- closeStatusAbnormalClosure = 1006
- closeStatusBadMessageData = 1007
- closeStatusPolicyViolation = 1008
- closeStatusTooBigData = 1009
- closeStatusExtensionMismatch = 1010
-
- maxControlFramePayloadLength = 125
-)
-
-var (
- ErrBadMaskingKey = &ProtocolError{"bad masking key"}
- ErrBadPongMessage = &ProtocolError{"bad pong message"}
- ErrBadClosingStatus = &ProtocolError{"bad closing status"}
- ErrUnsupportedExtensions = &ProtocolError{"unsupported extensions"}
- ErrNotImplemented = &ProtocolError{"not implemented"}
-
- handshakeHeader = map[string]bool{
- "Host": true,
- "Upgrade": true,
- "Connection": true,
- "Sec-Websocket-Key": true,
- "Sec-Websocket-Origin": true,
- "Sec-Websocket-Version": true,
- "Sec-Websocket-Protocol": true,
- "Sec-Websocket-Accept": true,
- }
-)
-
-// A hybiFrameHeader is a frame header as defined in hybi draft.
-type hybiFrameHeader struct {
- Fin bool
- Rsv [3]bool
- OpCode byte
- Length int64
- MaskingKey []byte
-
- data *bytes.Buffer
-}
-
-// A hybiFrameReader is a reader for hybi frame.
-type hybiFrameReader struct {
- reader io.Reader
-
- header hybiFrameHeader
- pos int64
- length int
-}
-
-func (frame *hybiFrameReader) Read(msg []byte) (n int, err error) {
- n, err = frame.reader.Read(msg)
- if frame.header.MaskingKey != nil {
- for i := 0; i < n; i++ {
- msg[i] = msg[i] ^ frame.header.MaskingKey[frame.pos%4]
- frame.pos++
- }
- }
- return n, err
-}
-
-func (frame *hybiFrameReader) PayloadType() byte { return frame.header.OpCode }
-
-func (frame *hybiFrameReader) HeaderReader() io.Reader {
- if frame.header.data == nil {
- return nil
- }
- if frame.header.data.Len() == 0 {
- return nil
- }
- return frame.header.data
-}
-
-func (frame *hybiFrameReader) TrailerReader() io.Reader { return nil }
-
-func (frame *hybiFrameReader) Len() (n int) { return frame.length }
-
-// A hybiFrameReaderFactory creates new frame reader based on its frame type.
-type hybiFrameReaderFactory struct {
- *bufio.Reader
-}
-
-// NewFrameReader reads a frame header from the connection, and creates new reader for the frame.
-// See Section 5.2 Base Framing protocol for detail.
-// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5.2
-func (buf hybiFrameReaderFactory) NewFrameReader() (frame frameReader, err error) {
- hybiFrame := new(hybiFrameReader)
- frame = hybiFrame
- var header []byte
- var b byte
- // First byte. FIN/RSV1/RSV2/RSV3/OpCode(4bits)
- b, err = buf.ReadByte()
- if err != nil {
- return
- }
- header = append(header, b)
- hybiFrame.header.Fin = ((header[0] >> 7) & 1) != 0
- for i := 0; i < 3; i++ {
- j := uint(6 - i)
- hybiFrame.header.Rsv[i] = ((header[0] >> j) & 1) != 0
- }
- hybiFrame.header.OpCode = header[0] & 0x0f
-
- // Second byte. Mask/Payload len(7bits)
- b, err = buf.ReadByte()
- if err != nil {
- return
- }
- header = append(header, b)
- mask := (b & 0x80) != 0
- b &= 0x7f
- lengthFields := 0
- switch {
- case b <= 125: // Payload length 7bits.
- hybiFrame.header.Length = int64(b)
- case b == 126: // Payload length 7+16bits
- lengthFields = 2
- case b == 127: // Payload length 7+64bits
- lengthFields = 8
- }
- for i := 0; i < lengthFields; i++ {
- b, err = buf.ReadByte()
- if err != nil {
- return
- }
- if lengthFields == 8 && i == 0 { // MSB must be zero when 7+64 bits
- b &= 0x7f
- }
- header = append(header, b)
- hybiFrame.header.Length = hybiFrame.header.Length*256 + int64(b)
- }
- if mask {
- // Masking key. 4 bytes.
- for i := 0; i < 4; i++ {
- b, err = buf.ReadByte()
- if err != nil {
- return
- }
- header = append(header, b)
- hybiFrame.header.MaskingKey = append(hybiFrame.header.MaskingKey, b)
- }
- }
- hybiFrame.reader = io.LimitReader(buf.Reader, hybiFrame.header.Length)
- hybiFrame.header.data = bytes.NewBuffer(header)
- hybiFrame.length = len(header) + int(hybiFrame.header.Length)
- return
-}
-
-// A HybiFrameWriter is a writer for hybi frame.
-type hybiFrameWriter struct {
- writer *bufio.Writer
-
- header *hybiFrameHeader
-}
-
-func (frame *hybiFrameWriter) Write(msg []byte) (n int, err error) {
- var header []byte
- var b byte
- if frame.header.Fin {
- b |= 0x80
- }
- for i := 0; i < 3; i++ {
- if frame.header.Rsv[i] {
- j := uint(6 - i)
- b |= 1 << j
- }
- }
- b |= frame.header.OpCode
- header = append(header, b)
- if frame.header.MaskingKey != nil {
- b = 0x80
- } else {
- b = 0
- }
- lengthFields := 0
- length := len(msg)
- switch {
- case length <= 125:
- b |= byte(length)
- case length < 65536:
- b |= 126
- lengthFields = 2
- default:
- b |= 127
- lengthFields = 8
- }
- header = append(header, b)
- for i := 0; i < lengthFields; i++ {
- j := uint((lengthFields - i - 1) * 8)
- b = byte((length >> j) & 0xff)
- header = append(header, b)
- }
- if frame.header.MaskingKey != nil {
- if len(frame.header.MaskingKey) != 4 {
- return 0, ErrBadMaskingKey
- }
- header = append(header, frame.header.MaskingKey...)
- frame.writer.Write(header)
- data := make([]byte, length)
- for i := range data {
- data[i] = msg[i] ^ frame.header.MaskingKey[i%4]
- }
- frame.writer.Write(data)
- err = frame.writer.Flush()
- return length, err
- }
- frame.writer.Write(header)
- frame.writer.Write(msg)
- err = frame.writer.Flush()
- return length, err
-}
-
-func (frame *hybiFrameWriter) Close() error { return nil }
-
-type hybiFrameWriterFactory struct {
- *bufio.Writer
- needMaskingKey bool
-}
-
-func (buf hybiFrameWriterFactory) NewFrameWriter(payloadType byte) (frame frameWriter, err error) {
- frameHeader := &hybiFrameHeader{Fin: true, OpCode: payloadType}
- if buf.needMaskingKey {
- frameHeader.MaskingKey, err = generateMaskingKey()
- if err != nil {
- return nil, err
- }
- }
- return &hybiFrameWriter{writer: buf.Writer, header: frameHeader}, nil
-}
-
-type hybiFrameHandler struct {
- conn *Conn
- payloadType byte
-}
-
-func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (frameReader, error) {
- if handler.conn.IsServerConn() {
- // The client MUST mask all frames sent to the server.
- if frame.(*hybiFrameReader).header.MaskingKey == nil {
- handler.WriteClose(closeStatusProtocolError)
- return nil, io.EOF
- }
- } else {
- // The server MUST NOT mask all frames.
- if frame.(*hybiFrameReader).header.MaskingKey != nil {
- handler.WriteClose(closeStatusProtocolError)
- return nil, io.EOF
- }
- }
- if header := frame.HeaderReader(); header != nil {
- io.Copy(ioutil.Discard, header)
- }
- switch frame.PayloadType() {
- case ContinuationFrame:
- frame.(*hybiFrameReader).header.OpCode = handler.payloadType
- case TextFrame, BinaryFrame:
- handler.payloadType = frame.PayloadType()
- case CloseFrame:
- return nil, io.EOF
- case PingFrame, PongFrame:
- b := make([]byte, maxControlFramePayloadLength)
- n, err := io.ReadFull(frame, b)
- if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
- return nil, err
- }
- io.Copy(ioutil.Discard, frame)
- if frame.PayloadType() == PingFrame {
- if _, err := handler.WritePong(b[:n]); err != nil {
- return nil, err
- }
- }
- return nil, nil
- }
- return frame, nil
-}
-
-func (handler *hybiFrameHandler) WriteClose(status int) (err error) {
- handler.conn.wio.Lock()
- defer handler.conn.wio.Unlock()
- w, err := handler.conn.frameWriterFactory.NewFrameWriter(CloseFrame)
- if err != nil {
- return err
- }
- msg := make([]byte, 2)
- binary.BigEndian.PutUint16(msg, uint16(status))
- _, err = w.Write(msg)
- w.Close()
- return err
-}
-
-func (handler *hybiFrameHandler) WritePong(msg []byte) (n int, err error) {
- handler.conn.wio.Lock()
- defer handler.conn.wio.Unlock()
- w, err := handler.conn.frameWriterFactory.NewFrameWriter(PongFrame)
- if err != nil {
- return 0, err
- }
- n, err = w.Write(msg)
- w.Close()
- return n, err
-}
-
-// newHybiConn creates a new WebSocket connection speaking hybi draft protocol.
-func newHybiConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
- if buf == nil {
- br := bufio.NewReader(rwc)
- bw := bufio.NewWriter(rwc)
- buf = bufio.NewReadWriter(br, bw)
- }
- ws := &Conn{config: config, request: request, buf: buf, rwc: rwc,
- frameReaderFactory: hybiFrameReaderFactory{buf.Reader},
- frameWriterFactory: hybiFrameWriterFactory{
- buf.Writer, request == nil},
- PayloadType: TextFrame,
- defaultCloseStatus: closeStatusNormal}
- ws.frameHandler = &hybiFrameHandler{conn: ws}
- return ws
-}
-
-// generateMaskingKey generates a masking key for a frame.
-func generateMaskingKey() (maskingKey []byte, err error) {
- maskingKey = make([]byte, 4)
- if _, err = io.ReadFull(rand.Reader, maskingKey); err != nil {
- return
- }
- return
-}
-
-// generateNonce generates a nonce consisting of a randomly selected 16-byte
-// value that has been base64-encoded.
-func generateNonce() (nonce []byte) {
- key := make([]byte, 16)
- if _, err := io.ReadFull(rand.Reader, key); err != nil {
- panic(err)
- }
- nonce = make([]byte, 24)
- base64.StdEncoding.Encode(nonce, key)
- return
-}
-
-// removeZone removes IPv6 zone identifer from host.
-// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
-func removeZone(host string) string {
- if !strings.HasPrefix(host, "[") {
- return host
- }
- i := strings.LastIndex(host, "]")
- if i < 0 {
- return host
- }
- j := strings.LastIndex(host[:i], "%")
- if j < 0 {
- return host
- }
- return host[:j] + host[i:]
-}
-
-// getNonceAccept computes the base64-encoded SHA-1 of the concatenation of
-// the nonce ("Sec-WebSocket-Key" value) with the websocket GUID string.
-func getNonceAccept(nonce []byte) (expected []byte, err error) {
- h := sha1.New()
- if _, err = h.Write(nonce); err != nil {
- return
- }
- if _, err = h.Write([]byte(websocketGUID)); err != nil {
- return
- }
- expected = make([]byte, 28)
- base64.StdEncoding.Encode(expected, h.Sum(nil))
- return
-}
-
-// Client handshake described in draft-ietf-hybi-thewebsocket-protocol-17
-func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) {
- bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n")
-
- // According to RFC 6874, an HTTP client, proxy, or other
- // intermediary must remove any IPv6 zone identifier attached
- // to an outgoing URI.
- bw.WriteString("Host: " + removeZone(config.Location.Host) + "\r\n")
- bw.WriteString("Upgrade: websocket\r\n")
- bw.WriteString("Connection: Upgrade\r\n")
- nonce := generateNonce()
- if config.handshakeData != nil {
- nonce = []byte(config.handshakeData["key"])
- }
- bw.WriteString("Sec-WebSocket-Key: " + string(nonce) + "\r\n")
- bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n")
-
- if config.Version != ProtocolVersionHybi13 {
- return ErrBadProtocolVersion
- }
-
- bw.WriteString("Sec-WebSocket-Version: " + fmt.Sprintf("%d", config.Version) + "\r\n")
- if len(config.Protocol) > 0 {
- bw.WriteString("Sec-WebSocket-Protocol: " + strings.Join(config.Protocol, ", ") + "\r\n")
- }
- // TODO(ukai): send Sec-WebSocket-Extensions.
- err = config.Header.WriteSubset(bw, handshakeHeader)
- if err != nil {
- return err
- }
-
- bw.WriteString("\r\n")
- if err = bw.Flush(); err != nil {
- return err
- }
-
- resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
- if err != nil {
- return err
- }
- if resp.StatusCode != 101 {
- return ErrBadStatus
- }
- if strings.ToLower(resp.Header.Get("Upgrade")) != "websocket" ||
- strings.ToLower(resp.Header.Get("Connection")) != "upgrade" {
- return ErrBadUpgrade
- }
- expectedAccept, err := getNonceAccept(nonce)
- if err != nil {
- return err
- }
- if resp.Header.Get("Sec-WebSocket-Accept") != string(expectedAccept) {
- return ErrChallengeResponse
- }
- if resp.Header.Get("Sec-WebSocket-Extensions") != "" {
- return ErrUnsupportedExtensions
- }
- offeredProtocol := resp.Header.Get("Sec-WebSocket-Protocol")
- if offeredProtocol != "" {
- protocolMatched := false
- for i := 0; i < len(config.Protocol); i++ {
- if config.Protocol[i] == offeredProtocol {
- protocolMatched = true
- break
- }
- }
- if !protocolMatched {
- return ErrBadWebSocketProtocol
- }
- config.Protocol = []string{offeredProtocol}
- }
-
- return nil
-}
-
-// newHybiClientConn creates a client WebSocket connection after handshake.
-func newHybiClientConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
- return newHybiConn(config, buf, rwc, nil)
-}
-
-// A HybiServerHandshaker performs a server handshake using hybi draft protocol.
-type hybiServerHandshaker struct {
- *Config
- accept []byte
-}
-
-func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) {
- c.Version = ProtocolVersionHybi13
- if req.Method != "GET" {
- return http.StatusMethodNotAllowed, ErrBadRequestMethod
- }
- // HTTP version can be safely ignored.
-
- if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" ||
- !strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade") {
- return http.StatusBadRequest, ErrNotWebSocket
- }
-
- key := req.Header.Get("Sec-Websocket-Key")
- if key == "" {
- return http.StatusBadRequest, ErrChallengeResponse
- }
- version := req.Header.Get("Sec-Websocket-Version")
- switch version {
- case "13":
- c.Version = ProtocolVersionHybi13
- default:
- return http.StatusBadRequest, ErrBadWebSocketVersion
- }
- var scheme string
- if req.TLS != nil {
- scheme = "wss"
- } else {
- scheme = "ws"
- }
- c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI())
- if err != nil {
- return http.StatusBadRequest, err
- }
- protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol"))
- if protocol != "" {
- protocols := strings.Split(protocol, ",")
- for i := 0; i < len(protocols); i++ {
- c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i]))
- }
- }
- c.accept, err = getNonceAccept([]byte(key))
- if err != nil {
- return http.StatusInternalServerError, err
- }
- return http.StatusSwitchingProtocols, nil
-}
-
-// Origin parses the Origin header in req.
-// If the Origin header is not set, it returns nil and nil.
-func Origin(config *Config, req *http.Request) (*url.URL, error) {
- var origin string
- switch config.Version {
- case ProtocolVersionHybi13:
- origin = req.Header.Get("Origin")
- }
- if origin == "" {
- return nil, nil
- }
- return url.ParseRequestURI(origin)
-}
-
-func (c *hybiServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) {
- if len(c.Protocol) > 0 {
- if len(c.Protocol) != 1 {
- // You need choose a Protocol in Handshake func in Server.
- return ErrBadWebSocketProtocol
- }
- }
- buf.WriteString("HTTP/1.1 101 Switching Protocols\r\n")
- buf.WriteString("Upgrade: websocket\r\n")
- buf.WriteString("Connection: Upgrade\r\n")
- buf.WriteString("Sec-WebSocket-Accept: " + string(c.accept) + "\r\n")
- if len(c.Protocol) > 0 {
- buf.WriteString("Sec-WebSocket-Protocol: " + c.Protocol[0] + "\r\n")
- }
- // TODO(ukai): send Sec-WebSocket-Extensions.
- if c.Header != nil {
- err := c.Header.WriteSubset(buf, handshakeHeader)
- if err != nil {
- return err
- }
- }
- buf.WriteString("\r\n")
- return buf.Flush()
-}
-
-func (c *hybiServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
- return newHybiServerConn(c.Config, buf, rwc, request)
-}
-
-// newHybiServerConn returns a new WebSocket connection speaking hybi draft protocol.
-func newHybiServerConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
- return newHybiConn(config, buf, rwc, request)
-}
diff --git a/vendor/golang.org/x/net/websocket/server.go b/vendor/golang.org/x/net/websocket/server.go
deleted file mode 100644
index 0895dea..0000000
--- a/vendor/golang.org/x/net/websocket/server.go
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "bufio"
- "fmt"
- "io"
- "net/http"
-)
-
-func newServerConn(rwc io.ReadWriteCloser, buf *bufio.ReadWriter, req *http.Request, config *Config, handshake func(*Config, *http.Request) error) (conn *Conn, err error) {
- var hs serverHandshaker = &hybiServerHandshaker{Config: config}
- code, err := hs.ReadHandshake(buf.Reader, req)
- if err == ErrBadWebSocketVersion {
- fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
- fmt.Fprintf(buf, "Sec-WebSocket-Version: %s\r\n", SupportedProtocolVersion)
- buf.WriteString("\r\n")
- buf.WriteString(err.Error())
- buf.Flush()
- return
- }
- if err != nil {
- fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
- buf.WriteString("\r\n")
- buf.WriteString(err.Error())
- buf.Flush()
- return
- }
- if handshake != nil {
- err = handshake(config, req)
- if err != nil {
- code = http.StatusForbidden
- fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
- buf.WriteString("\r\n")
- buf.Flush()
- return
- }
- }
- err = hs.AcceptHandshake(buf.Writer)
- if err != nil {
- code = http.StatusBadRequest
- fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
- buf.WriteString("\r\n")
- buf.Flush()
- return
- }
- conn = hs.NewServerConn(buf, rwc, req)
- return
-}
-
-// Server represents a server of a WebSocket.
-type Server struct {
- // Config is a WebSocket configuration for new WebSocket connection.
- Config
-
- // Handshake is an optional function in WebSocket handshake.
- // For example, you can check, or don't check Origin header.
- // Another example, you can select config.Protocol.
- Handshake func(*Config, *http.Request) error
-
- // Handler handles a WebSocket connection.
- Handler
-}
-
-// ServeHTTP implements the http.Handler interface for a WebSocket
-func (s Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
- s.serveWebSocket(w, req)
-}
-
-func (s Server) serveWebSocket(w http.ResponseWriter, req *http.Request) {
- rwc, buf, err := w.(http.Hijacker).Hijack()
- if err != nil {
- panic("Hijack failed: " + err.Error())
- }
- // The server should abort the WebSocket connection if it finds
- // the client did not send a handshake that matches with protocol
- // specification.
- defer rwc.Close()
- conn, err := newServerConn(rwc, buf, req, &s.Config, s.Handshake)
- if err != nil {
- return
- }
- if conn == nil {
- panic("unexpected nil conn")
- }
- s.Handler(conn)
-}
-
-// Handler is a simple interface to a WebSocket browser client.
-// It checks if Origin header is valid URL by default.
-// You might want to verify websocket.Conn.Config().Origin in the func.
-// If you use Server instead of Handler, you could call websocket.Origin and
-// check the origin in your Handshake func. So, if you want to accept
-// non-browser clients, which do not send an Origin header, set a
-// Server.Handshake that does not check the origin.
-type Handler func(*Conn)
-
-func checkOrigin(config *Config, req *http.Request) (err error) {
- config.Origin, err = Origin(config, req)
- if err == nil && config.Origin == nil {
- return fmt.Errorf("null origin")
- }
- return err
-}
-
-// ServeHTTP implements the http.Handler interface for a WebSocket
-func (h Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
- s := Server{Handler: h, Handshake: checkOrigin}
- s.serveWebSocket(w, req)
-}
diff --git a/vendor/golang.org/x/net/websocket/websocket.go b/vendor/golang.org/x/net/websocket/websocket.go
deleted file mode 100644
index 1f4f7be..0000000
--- a/vendor/golang.org/x/net/websocket/websocket.go
+++ /dev/null
@@ -1,451 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package websocket implements a client and server for the WebSocket protocol
-// as specified in RFC 6455.
-//
-// This package currently lacks some features found in an alternative
-// and more actively maintained WebSocket package:
-//
-// https://godoc.org/github.com/gorilla/websocket
-//
-package websocket // import "golang.org/x/net/websocket"
-
-import (
- "bufio"
- "crypto/tls"
- "encoding/json"
- "errors"
- "io"
- "io/ioutil"
- "net"
- "net/http"
- "net/url"
- "sync"
- "time"
-)
-
-const (
- ProtocolVersionHybi13 = 13
- ProtocolVersionHybi = ProtocolVersionHybi13
- SupportedProtocolVersion = "13"
-
- ContinuationFrame = 0
- TextFrame = 1
- BinaryFrame = 2
- CloseFrame = 8
- PingFrame = 9
- PongFrame = 10
- UnknownFrame = 255
-
- DefaultMaxPayloadBytes = 32 << 20 // 32MB
-)
-
-// ProtocolError represents WebSocket protocol errors.
-type ProtocolError struct {
- ErrorString string
-}
-
-func (err *ProtocolError) Error() string { return err.ErrorString }
-
-var (
- ErrBadProtocolVersion = &ProtocolError{"bad protocol version"}
- ErrBadScheme = &ProtocolError{"bad scheme"}
- ErrBadStatus = &ProtocolError{"bad status"}
- ErrBadUpgrade = &ProtocolError{"missing or bad upgrade"}
- ErrBadWebSocketOrigin = &ProtocolError{"missing or bad WebSocket-Origin"}
- ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"}
- ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"}
- ErrBadWebSocketVersion = &ProtocolError{"missing or bad WebSocket Version"}
- ErrChallengeResponse = &ProtocolError{"mismatch challenge/response"}
- ErrBadFrame = &ProtocolError{"bad frame"}
- ErrBadFrameBoundary = &ProtocolError{"not on frame boundary"}
- ErrNotWebSocket = &ProtocolError{"not websocket protocol"}
- ErrBadRequestMethod = &ProtocolError{"bad method"}
- ErrNotSupported = &ProtocolError{"not supported"}
-)
-
-// ErrFrameTooLarge is returned by Codec's Receive method if payload size
-// exceeds limit set by Conn.MaxPayloadBytes
-var ErrFrameTooLarge = errors.New("websocket: frame payload size exceeds limit")
-
-// Addr is an implementation of net.Addr for WebSocket.
-type Addr struct {
- *url.URL
-}
-
-// Network returns the network type for a WebSocket, "websocket".
-func (addr *Addr) Network() string { return "websocket" }
-
-// Config is a WebSocket configuration
-type Config struct {
- // A WebSocket server address.
- Location *url.URL
-
- // A Websocket client origin.
- Origin *url.URL
-
- // WebSocket subprotocols.
- Protocol []string
-
- // WebSocket protocol version.
- Version int
-
- // TLS config for secure WebSocket (wss).
- TlsConfig *tls.Config
-
- // Additional header fields to be sent in WebSocket opening handshake.
- Header http.Header
-
- // Dialer used when opening websocket connections.
- Dialer *net.Dialer
-
- handshakeData map[string]string
-}
-
-// serverHandshaker is an interface to handle WebSocket server side handshake.
-type serverHandshaker interface {
- // ReadHandshake reads handshake request message from client.
- // Returns http response code and error if any.
- ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error)
-
- // AcceptHandshake accepts the client handshake request and sends
- // handshake response back to client.
- AcceptHandshake(buf *bufio.Writer) (err error)
-
- // NewServerConn creates a new WebSocket connection.
- NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn)
-}
-
-// frameReader is an interface to read a WebSocket frame.
-type frameReader interface {
- // Reader is to read payload of the frame.
- io.Reader
-
- // PayloadType returns payload type.
- PayloadType() byte
-
- // HeaderReader returns a reader to read header of the frame.
- HeaderReader() io.Reader
-
- // TrailerReader returns a reader to read trailer of the frame.
- // If it returns nil, there is no trailer in the frame.
- TrailerReader() io.Reader
-
- // Len returns total length of the frame, including header and trailer.
- Len() int
-}
-
-// frameReaderFactory is an interface to creates new frame reader.
-type frameReaderFactory interface {
- NewFrameReader() (r frameReader, err error)
-}
-
-// frameWriter is an interface to write a WebSocket frame.
-type frameWriter interface {
- // Writer is to write payload of the frame.
- io.WriteCloser
-}
-
-// frameWriterFactory is an interface to create new frame writer.
-type frameWriterFactory interface {
- NewFrameWriter(payloadType byte) (w frameWriter, err error)
-}
-
-type frameHandler interface {
- HandleFrame(frame frameReader) (r frameReader, err error)
- WriteClose(status int) (err error)
-}
-
-// Conn represents a WebSocket connection.
-//
-// Multiple goroutines may invoke methods on a Conn simultaneously.
-type Conn struct {
- config *Config
- request *http.Request
-
- buf *bufio.ReadWriter
- rwc io.ReadWriteCloser
-
- rio sync.Mutex
- frameReaderFactory
- frameReader
-
- wio sync.Mutex
- frameWriterFactory
-
- frameHandler
- PayloadType byte
- defaultCloseStatus int
-
- // MaxPayloadBytes limits the size of frame payload received over Conn
- // by Codec's Receive method. If zero, DefaultMaxPayloadBytes is used.
- MaxPayloadBytes int
-}
-
-// Read implements the io.Reader interface:
-// it reads data of a frame from the WebSocket connection.
-// if msg is not large enough for the frame data, it fills the msg and next Read
-// will read the rest of the frame data.
-// it reads Text frame or Binary frame.
-func (ws *Conn) Read(msg []byte) (n int, err error) {
- ws.rio.Lock()
- defer ws.rio.Unlock()
-again:
- if ws.frameReader == nil {
- frame, err := ws.frameReaderFactory.NewFrameReader()
- if err != nil {
- return 0, err
- }
- ws.frameReader, err = ws.frameHandler.HandleFrame(frame)
- if err != nil {
- return 0, err
- }
- if ws.frameReader == nil {
- goto again
- }
- }
- n, err = ws.frameReader.Read(msg)
- if err == io.EOF {
- if trailer := ws.frameReader.TrailerReader(); trailer != nil {
- io.Copy(ioutil.Discard, trailer)
- }
- ws.frameReader = nil
- goto again
- }
- return n, err
-}
-
-// Write implements the io.Writer interface:
-// it writes data as a frame to the WebSocket connection.
-func (ws *Conn) Write(msg []byte) (n int, err error) {
- ws.wio.Lock()
- defer ws.wio.Unlock()
- w, err := ws.frameWriterFactory.NewFrameWriter(ws.PayloadType)
- if err != nil {
- return 0, err
- }
- n, err = w.Write(msg)
- w.Close()
- return n, err
-}
-
-// Close implements the io.Closer interface.
-func (ws *Conn) Close() error {
- err := ws.frameHandler.WriteClose(ws.defaultCloseStatus)
- err1 := ws.rwc.Close()
- if err != nil {
- return err
- }
- return err1
-}
-
-// IsClientConn reports whether ws is a client-side connection.
-func (ws *Conn) IsClientConn() bool { return ws.request == nil }
-
-// IsServerConn reports whether ws is a server-side connection.
-func (ws *Conn) IsServerConn() bool { return ws.request != nil }
-
-// LocalAddr returns the WebSocket Origin for the connection for client, or
-// the WebSocket location for server.
-func (ws *Conn) LocalAddr() net.Addr {
- if ws.IsClientConn() {
- return &Addr{ws.config.Origin}
- }
- return &Addr{ws.config.Location}
-}
-
-// RemoteAddr returns the WebSocket location for the connection for client, or
-// the Websocket Origin for server.
-func (ws *Conn) RemoteAddr() net.Addr {
- if ws.IsClientConn() {
- return &Addr{ws.config.Location}
- }
- return &Addr{ws.config.Origin}
-}
-
-var errSetDeadline = errors.New("websocket: cannot set deadline: not using a net.Conn")
-
-// SetDeadline sets the connection's network read & write deadlines.
-func (ws *Conn) SetDeadline(t time.Time) error {
- if conn, ok := ws.rwc.(net.Conn); ok {
- return conn.SetDeadline(t)
- }
- return errSetDeadline
-}
-
-// SetReadDeadline sets the connection's network read deadline.
-func (ws *Conn) SetReadDeadline(t time.Time) error {
- if conn, ok := ws.rwc.(net.Conn); ok {
- return conn.SetReadDeadline(t)
- }
- return errSetDeadline
-}
-
-// SetWriteDeadline sets the connection's network write deadline.
-func (ws *Conn) SetWriteDeadline(t time.Time) error {
- if conn, ok := ws.rwc.(net.Conn); ok {
- return conn.SetWriteDeadline(t)
- }
- return errSetDeadline
-}
-
-// Config returns the WebSocket config.
-func (ws *Conn) Config() *Config { return ws.config }
-
-// Request returns the http request upgraded to the WebSocket.
-// It is nil for client side.
-func (ws *Conn) Request() *http.Request { return ws.request }
-
-// Codec represents a symmetric pair of functions that implement a codec.
-type Codec struct {
- Marshal func(v interface{}) (data []byte, payloadType byte, err error)
- Unmarshal func(data []byte, payloadType byte, v interface{}) (err error)
-}
-
-// Send sends v marshaled by cd.Marshal as single frame to ws.
-func (cd Codec) Send(ws *Conn, v interface{}) (err error) {
- data, payloadType, err := cd.Marshal(v)
- if err != nil {
- return err
- }
- ws.wio.Lock()
- defer ws.wio.Unlock()
- w, err := ws.frameWriterFactory.NewFrameWriter(payloadType)
- if err != nil {
- return err
- }
- _, err = w.Write(data)
- w.Close()
- return err
-}
-
-// Receive receives single frame from ws, unmarshaled by cd.Unmarshal and stores
-// in v. The whole frame payload is read to an in-memory buffer; max size of
-// payload is defined by ws.MaxPayloadBytes. If frame payload size exceeds
-// limit, ErrFrameTooLarge is returned; in this case frame is not read off wire
-// completely. The next call to Receive would read and discard leftover data of
-// previous oversized frame before processing next frame.
-func (cd Codec) Receive(ws *Conn, v interface{}) (err error) {
- ws.rio.Lock()
- defer ws.rio.Unlock()
- if ws.frameReader != nil {
- _, err = io.Copy(ioutil.Discard, ws.frameReader)
- if err != nil {
- return err
- }
- ws.frameReader = nil
- }
-again:
- frame, err := ws.frameReaderFactory.NewFrameReader()
- if err != nil {
- return err
- }
- frame, err = ws.frameHandler.HandleFrame(frame)
- if err != nil {
- return err
- }
- if frame == nil {
- goto again
- }
- maxPayloadBytes := ws.MaxPayloadBytes
- if maxPayloadBytes == 0 {
- maxPayloadBytes = DefaultMaxPayloadBytes
- }
- if hf, ok := frame.(*hybiFrameReader); ok && hf.header.Length > int64(maxPayloadBytes) {
- // payload size exceeds limit, no need to call Unmarshal
- //
- // set frameReader to current oversized frame so that
- // the next call to this function can drain leftover
- // data before processing the next frame
- ws.frameReader = frame
- return ErrFrameTooLarge
- }
- payloadType := frame.PayloadType()
- data, err := ioutil.ReadAll(frame)
- if err != nil {
- return err
- }
- return cd.Unmarshal(data, payloadType, v)
-}
-
-func marshal(v interface{}) (msg []byte, payloadType byte, err error) {
- switch data := v.(type) {
- case string:
- return []byte(data), TextFrame, nil
- case []byte:
- return data, BinaryFrame, nil
- }
- return nil, UnknownFrame, ErrNotSupported
-}
-
-func unmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
- switch data := v.(type) {
- case *string:
- *data = string(msg)
- return nil
- case *[]byte:
- *data = msg
- return nil
- }
- return ErrNotSupported
-}
-
-/*
-Message is a codec to send/receive text/binary data in a frame on WebSocket connection.
-To send/receive text frame, use string type.
-To send/receive binary frame, use []byte type.
-
-Trivial usage:
-
- import "websocket"
-
- // receive text frame
- var message string
- websocket.Message.Receive(ws, &message)
-
- // send text frame
- message = "hello"
- websocket.Message.Send(ws, message)
-
- // receive binary frame
- var data []byte
- websocket.Message.Receive(ws, &data)
-
- // send binary frame
- data = []byte{0, 1, 2}
- websocket.Message.Send(ws, data)
-
-*/
-var Message = Codec{marshal, unmarshal}
-
-func jsonMarshal(v interface{}) (msg []byte, payloadType byte, err error) {
- msg, err = json.Marshal(v)
- return msg, TextFrame, err
-}
-
-func jsonUnmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
- return json.Unmarshal(msg, v)
-}
-
-/*
-JSON is a codec to send/receive JSON data in a frame from a WebSocket connection.
-
-Trivial usage:
-
- import "websocket"
-
- type T struct {
- Msg string
- Count int
- }
-
- // receive JSON type T
- var data T
- websocket.JSON.Receive(ws, &data)
-
- // send JSON type T
- websocket.JSON.Send(ws, data)
-*/
-var JSON = Codec{jsonMarshal, jsonUnmarshal}
diff --git a/vendor/vendor.json b/vendor/vendor.json
deleted file mode 100644
index 54a8a83..0000000
--- a/vendor/vendor.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "comment": "",
- "ignore": "test",
- "package": [
- {
- "checksumSHA1": "F+tqxPGFt5x7DKZakbbMmENX1oQ=",
- "path": "golang.org/x/net/websocket",
- "revision": "ca1201d0de80cfde86cb01aea620983605dfe99b",
- "revisionTime": "2019-07-23T18:48:14Z",
- "tree": true
- }
- ],
- "rootPath": "go-stress-testing"
-}
From 1f530a7f92e367ed53d71cc95c66d1a0f5b6fe77 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Sat, 4 Jul 2020 11:11:20 +0800
Subject: [PATCH 43/75] fix
---
.gitignore | 3 ++-
server/client/http_client.go | 5 ++++-
server/golink/http_link.go | 9 +++------
3 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/.gitignore b/.gitignore
index ca38fc5..2f4c6ac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,4 +18,5 @@ go-stress-testing-mac
go-stress-testing-linux
go-stress-testing-win.exe
model/modeltest/*
-model/modeltest*
\ No newline at end of file
+model/modeltest*
+server.go
\ No newline at end of file
diff --git a/server/client/http_client.go b/server/client/http_client.go
index 48f5c18..de4f3e8 100644
--- a/server/client/http_client.go
+++ b/server/client/http_client.go
@@ -10,6 +10,7 @@ package client
import (
"crypto/tls"
"fmt"
+ "go-stress-testing/heper"
"io"
"net/http"
"time"
@@ -21,7 +22,7 @@ import (
// body 请求的body
// headers 请求头信息
// timeout 请求超时时间
-func HttpRequest(method, url string, body io.Reader, headers map[string]string, timeout time.Duration) (resp *http.Response, err error) {
+func HttpRequest(method, url string, body io.Reader, headers map[string]string, timeout time.Duration) (resp *http.Response, requestTime uint64, err error) {
// 跳过证书验证
tr := &http.Transport{
@@ -51,7 +52,9 @@ func HttpRequest(method, url string, body io.Reader, headers map[string]string,
req.Header.Set(key, value)
}
+ startTime := time.Now()
resp, err = client.Do(req)
+ requestTime = uint64(heper.DiffNano(startTime))
if err != nil {
fmt.Println("请求失败:", err)
diff --git a/server/golink/http_link.go b/server/golink/http_link.go
index 4b7f223..260c50b 100644
--- a/server/golink/http_link.go
+++ b/server/golink/http_link.go
@@ -8,11 +8,9 @@
package golink
import (
- "go-stress-testing/heper"
"go-stress-testing/model"
"go-stress-testing/server/client"
"sync"
- "time"
)
// http go link
@@ -26,14 +24,13 @@ func Http(chanId uint64, ch chan<- *model.RequestResults, totalNumber uint64, wg
for i := uint64(0); i < totalNumber; i++ {
var (
- startTime = time.Now()
+ // startTime = time.Now()
isSucceed = false
errCode = model.HttpOk
)
- resp, err := client.HttpRequest(request.Method, request.Url, request.GetBody(), request.Headers, request.Timeout)
- requestTime := uint64(heper.DiffNano(startTime))
- // resp, err := server.HttpGetResp(request.Url)
+ resp, requestTime, err := client.HttpRequest(request.Method, request.Url, request.GetBody(), request.Headers, request.Timeout)
+ // requestTime := uint64(heper.DiffNano(startTime))
if err != nil {
errCode = model.RequestErr // 请求错误
} else {
From 3525e721558ed8e16387ef7d48ab40988155cb1c Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Sat, 18 Jul 2020 10:18:03 +0800
Subject: [PATCH 44/75] =?UTF-8?q?=E6=96=B0=E7=89=88postman=20curl=E9=80=82?=
=?UTF-8?q?=E9=85=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
model/curl_model.go | 42 ++++++++++++++++++++++++++++++++----------
1 file changed, 32 insertions(+), 10 deletions(-)
diff --git a/model/curl_model.go b/model/curl_model.go
index 8a8bc12..320aaff 100644
--- a/model/curl_model.go
+++ b/model/curl_model.go
@@ -121,10 +121,15 @@ func ParseTheFile(path string) (curl *CURL, err error) {
index = strings.Index(data, endSymbol)
if index <= -1 {
- break
+ index = len(data)
+ // break
}
value = data[:index]
- data = data[index+1:]
+ if len(data) >= index+1 {
+ data = data[index+1:]
+ } else {
+ data = ""
+ }
// 去除首尾空格
data = strings.TrimFunc(data, func(r rune) bool {
@@ -135,12 +140,17 @@ func ParseTheFile(path string) (curl *CURL, err error) {
return false
})
+ if key == "" {
+ continue
+ }
+
curl.Data[key] = append(curl.Data[key], value)
// break
}
+ // debug
// for key, value := range curl.Data {
// fmt.Println("key:", key, "value:", value)
// }
@@ -157,7 +167,7 @@ func (c *CURL) String() (url string) {
// GetUrl
func (c *CURL) GetUrl() (url string) {
- keys := []string{"curl","--url"}
+ keys := []string{"curl", "--url"}
value := c.getDataValue(keys)
if len(value) <= 0 {
@@ -173,17 +183,14 @@ func (c *CURL) GetUrl() (url string) {
func (c *CURL) GetMethod() (method string) {
method = "GET"
- var (
- postKeys = []string{"--d", "--data", "--data-binary $", "--data-binary"}
- )
- value := c.getDataValue(postKeys)
+ body := c.GetBody()
- if len(value) >= 1 {
+ if len(body) > 0 {
return "POST"
}
keys := []string{"-X", "--request"}
- value = c.getDataValue(keys)
+ value := c.getDataValue(keys)
if len(value) <= 0 {
@@ -220,10 +227,11 @@ func (c *CURL) GetHeadersStr() string {
// 获取body
func (c *CURL) GetBody() (body string) {
- keys := []string{"--data", "-d", "--data-raw", "--data-binary"}
+ keys := []string{"--data", "-d", "--data-urlencode", "--data-raw", "--data-binary"}
value := c.getDataValue(keys)
if len(value) <= 0 {
+ body = c.getPostForm()
return
}
@@ -233,3 +241,17 @@ func (c *CURL) GetBody() (body string) {
return
}
+
+func (c *CURL) getPostForm() (body string) {
+ keys := []string{"--form", "-F", "--form-string"}
+ value := c.getDataValue(keys)
+
+ if len(value) <= 0 {
+
+ return
+ }
+
+ body = strings.Join(value, "&")
+
+ return
+}
From 760552c7c1e951134cf65b0d6d78274365edbfa1 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Sat, 1 Aug 2020 09:43:21 +0800
Subject: [PATCH 45/75] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8E=A5=E5=8F=A3?=
=?UTF-8?q?=E5=8A=A0=E6=9D=83=E5=8E=8B=E6=B5=8B=E5=92=8C=E5=88=86=E6=AD=A5?=
=?UTF-8?q?=E5=8E=8B=E6=B5=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
model/request_model.go | 40 +++++++----
server/golink/http_link.go | 59 ++++++++++++-----
server/golink/http_link_many.go | 82 +++++++++++++++++++++++
server/golink/http_link_weigh.go | 110 +++++++++++++++++++++++++++++++
server/golink/websocket_link.go | 7 +-
tests/servers.go | 39 +++++++++++
6 files changed, 308 insertions(+), 29 deletions(-)
create mode 100644 server/golink/http_link_many.go
create mode 100644 server/golink/http_link_weigh.go
create mode 100644 tests/servers.go
diff --git a/model/request_model.go b/model/request_model.go
index e9b6fa6..e4c5ce9 100644
--- a/model/request_model.go
+++ b/model/request_model.go
@@ -68,12 +68,10 @@ type VerifyWebSocket func(request *Request, seq string, msg []byte) (code int, i
type Request struct {
Url string // Url
Form string // http/webSocket/tcp
- Method string // 方法 get/post/put
+ Method string // 方法 GET/POST/PUT
Headers map[string]string // Headers
Body string // body
Verify string // 验证的方法
- VerifyHttp VerifyHttp // 验证的方法
- VerifyWebSocket VerifyWebSocket // 验证的方法
Timeout time.Duration // 请求超时时间
Debug bool // 是否开启Debug模式
@@ -87,6 +85,31 @@ func (r *Request) GetBody() (body io.Reader) {
return
}
+func (r *Request) getVerifyKey() (key string) {
+ key = fmt.Sprintf("%s.%s", r.Form, r.Verify)
+
+ return
+}
+
+// 获取数据校验方法
+func (r *Request) GetVerifyHttp() VerifyHttp {
+ verify, ok := verifyMapHttp[r.getVerifyKey()]
+ if !ok {
+ panic("GetVerifyHttp 验证方法不存在:" + r.Verify)
+ }
+
+ return verify
+}
+
+func (r *Request) GetVerifyWebSocket() VerifyWebSocket {
+ verify, ok := verifyMapWebSocket[r.getVerifyKey()]
+ if !ok {
+ panic("GetVerifyWebSocket 验证方法不存在:" + r.Verify)
+ }
+
+ return verify
+}
+
// NewRequest
// url 压测的url
// verify 验证方法 在server/verify中 http 支持:statusCode、json webSocket支持:json
@@ -146,8 +169,6 @@ func NewRequest(url string, verify string, timeout time.Duration, debug bool, pa
}
var (
- verifyHttp VerifyHttp
- verifyWebSocket VerifyWebSocket
ok bool
)
@@ -159,7 +180,7 @@ func NewRequest(url string, verify string, timeout time.Duration, debug bool, pa
}
key := fmt.Sprintf("%s.%s", form, verify)
- verifyHttp, ok = verifyMapHttp[key]
+ _, ok = verifyMapHttp[key]
if !ok {
err = errors.New("验证器不存在:" + key)
@@ -172,7 +193,7 @@ func NewRequest(url string, verify string, timeout time.Duration, debug bool, pa
}
key := fmt.Sprintf("%s.%s", form, verify)
- verifyWebSocket, ok = verifyMapWebSocket[key]
+ _, ok = verifyMapWebSocket[key]
if !ok {
err = errors.New("验证器不存在:" + key)
@@ -192,8 +213,6 @@ func NewRequest(url string, verify string, timeout time.Duration, debug bool, pa
Headers: headers,
Body: body,
Verify: verify,
- VerifyHttp: verifyHttp,
- VerifyWebSocket: verifyWebSocket,
Timeout: timeout,
Debug: debug,
}
@@ -247,13 +266,12 @@ func (r *Request) IsParameterLegal() (err error) {
r.Verify = "json"
key := fmt.Sprintf("%s.%s", r.Form, r.Verify)
- value, ok := verifyMapHttp[key]
+ _, ok := verifyMapHttp[key]
if !ok {
return errors.New("验证器不存在:" + key)
}
- r.VerifyHttp = value
return
}
diff --git a/server/golink/http_link.go b/server/golink/http_link.go
index 260c50b..d922576 100644
--- a/server/golink/http_link.go
+++ b/server/golink/http_link.go
@@ -8,9 +8,10 @@
package golink
import (
+ "sync"
+
"go-stress-testing/model"
"go-stress-testing/server/client"
- "sync"
)
// http go link
@@ -23,20 +24,9 @@ func Http(chanId uint64, ch chan<- *model.RequestResults, totalNumber uint64, wg
// fmt.Printf("启动协程 编号:%05d \n", chanId)
for i := uint64(0); i < totalNumber; i++ {
- var (
- // startTime = time.Now()
- isSucceed = false
- errCode = model.HttpOk
- )
-
- resp, requestTime, err := client.HttpRequest(request.Method, request.Url, request.GetBody(), request.Headers, request.Timeout)
- // requestTime := uint64(heper.DiffNano(startTime))
- if err != nil {
- errCode = model.RequestErr // 请求错误
- } else {
- // 验证请求是否成功
- errCode, isSucceed = request.VerifyHttp(request, resp)
- }
+ list := getRequestList(request)
+
+ isSucceed, errCode, requestTime := sendList(list)
requestResults := &model.RequestResults{
Time: requestTime,
@@ -51,3 +41,42 @@ func Http(chanId uint64, ch chan<- *model.RequestResults, totalNumber uint64, wg
return
}
+// 多个接口分步压测
+func sendList(requestList []*model.Request) (isSucceed bool, errCode int, requestTime uint64) {
+
+ errCode = model.HttpOk
+ for _, request := range requestList {
+ succeed, code, u := send(request)
+ isSucceed = succeed
+ errCode = code
+ requestTime = requestTime + u
+ if succeed == false {
+
+ break
+ }
+ }
+
+ return
+}
+
+// send 发送一次请求
+func send(request *model.Request) (bool, int, uint64) {
+ var (
+ // startTime = time.Now()
+ isSucceed = false
+ errCode = model.HttpOk
+ )
+
+ newRequest := getRequest(request)
+ // newRequest := request
+
+ resp, requestTime, err := client.HttpRequest(newRequest.Method, newRequest.Url, newRequest.GetBody(), newRequest.Headers, newRequest.Timeout)
+ // requestTime := uint64(heper.DiffNano(startTime))
+ if err != nil {
+ errCode = model.RequestErr // 请求错误
+ } else {
+ // 验证请求是否成功
+ errCode, isSucceed = newRequest.GetVerifyHttp()(newRequest, resp)
+ }
+ return isSucceed, errCode, requestTime
+}
diff --git a/server/golink/http_link_many.go b/server/golink/http_link_many.go
new file mode 100644
index 0000000..427985d
--- /dev/null
+++ b/server/golink/http_link_many.go
@@ -0,0 +1,82 @@
+/**
+* Created by GoLand.
+* User: link1st
+* Date: 2020/7/31
+* Time: 8:36 下午
+ */
+
+package golink
+
+import (
+ "time"
+
+ "go-stress-testing/model"
+)
+
+// 接口分步压测
+type ReqListMany struct {
+ list []*model.Request
+}
+
+func (r *ReqListMany) getCount() int {
+ return len(r.list)
+}
+
+var (
+ clientList *ReqListMany
+)
+
+// 接口分步压测示例
+func init() {
+
+ clientList = &ReqListMany{}
+
+ // TODO::接口分步压测示例
+ // 需要压测的接口参数
+ clients := make([]*model.Request, 0)
+
+ // 压测第一步
+ clients = append(clients, &model.Request{
+ Url: "https://page.aliyun.com/delivery/plan/list", // 请求url
+ Form: "http", // 请求方式 示例参数:http/webSocket/tcp
+ Method: "POST", // 请求方法 示例参数:GET/POST/PUT
+ Headers: map[string]string{
+ "referer": "https://cn.aliyun.com/",
+ "cookie": "aliyun_choice=CN; JSESSIONID=J8866281-CKCFJ4BUZ7GDO9V89YBW1-KJ3J5V9K-GYUW7; maliyun_temporary_console0=1AbLByOMHeZe3G41KYd5WWZvrM%2BGErkaLcWfBbgveKA9ifboArprPASvFUUfhwHtt44qsDwVqMk8Wkdr1F5LccYk2mPCZJiXb0q%2Bllj5u3SQGQurtyPqnG489y%2FkoA%2FEvOwsXJTvXTFQPK%2BGJD4FJg%3D%3D; cna=L3Q5F8cHDGgCAXL3r8fEZtdU; isg=BFNThsmSCcgX-sUcc5Jo2s2T4tF9COfKYi8g9wVwr3KphHMmjdh3GrHFvPTqJD_C; l=eBaceXLnQGBjstRJBOfwPurza77OSIRAguPzaNbMiT5POw1B5WAlWZbqyNY6C3GVh6lwR37EODnaBeYBc3K-nxvOu9eFfGMmn",
+ }, // headers 头信息
+ Body: "adPlanQueryParam=%7B%22adZone%22%3A%7B%22positionList%22%3A%5B%7B%22positionId%22%3A83%7D%5D%7D%2C%22requestId%22%3A%2217958651-f205-44c7-ad5d-f8af92a6217a%22%7D", // 消息体
+ Verify: "statusCode", // 验证的方法 示例参数:statusCode、json
+ Timeout: 30 * time.Second, // 是否开启Debug模式
+ Debug: false, // 是否开启Debug模式
+ })
+
+ // 压测第二步
+ clients = append(clients, &model.Request{
+ Url: "https://page.aliyun.com/delivery/plan/list", // 请求url
+ Form: "http", // 请求方式 示例参数:http/webSocket/tcp
+ Method: "POST", // 请求方法 示例参数:GET/POST/PUT
+ Headers: map[string]string{
+ "referer": "https://cn.aliyun.com/",
+ "cookie": "aliyun_choice=CN; JSESSIONID=J8866281-CKCFJ4BUZ7GDO9V89YBW1-KJ3J5V9K-GYUW7; maliyun_temporary_console0=1AbLByOMHeZe3G41KYd5WWZvrM%2BGErkaLcWfBbgveKA9ifboArprPASvFUUfhwHtt44qsDwVqMk8Wkdr1F5LccYk2mPCZJiXb0q%2Bllj5u3SQGQurtyPqnG489y%2FkoA%2FEvOwsXJTvXTFQPK%2BGJD4FJg%3D%3D; cna=L3Q5F8cHDGgCAXL3r8fEZtdU; isg=BFNThsmSCcgX-sUcc5Jo2s2T4tF9COfKYi8g9wVwr3KphHMmjdh3GrHFvPTqJD_C; l=eBaceXLnQGBjstRJBOfwPurza77OSIRAguPzaNbMiT5POw1B5WAlWZbqyNY6C3GVh6lwR37EODnaBeYBc3K-nxvOu9eFfGMmn",
+ }, // headers 头信息
+ Body: "adPlanQueryParam=%7B%22adZone%22%3A%7B%22positionList%22%3A%5B%7B%22positionId%22%3A83%7D%5D%7D%2C%22requestId%22%3A%2217958651-f205-44c7-ad5d-f8af92a6217a%22%7D", // 消息体
+ Verify: "statusCode", // 验证的方法 示例参数:statusCode、json
+ Timeout: 30 * time.Second, // 是否开启Debug模式
+ Debug: false, // 是否开启Debug模式
+ })
+
+ clientList.list = clients
+
+ // TODO::注释下面一行代码
+ clientList.list = nil
+}
+
+func getRequestList(request *model.Request) []*model.Request {
+
+ if len(clientList.list) <= 0 {
+
+ return []*model.Request{request}
+ }
+
+ return clientList.list
+}
diff --git a/server/golink/http_link_weigh.go b/server/golink/http_link_weigh.go
new file mode 100644
index 0000000..8c59fcf
--- /dev/null
+++ b/server/golink/http_link_weigh.go
@@ -0,0 +1,110 @@
+/**
+* Created by GoLand.
+* User: link1st
+* Date: 2020/7/31
+* Time: 8:36 下午
+ */
+
+package golink
+
+import (
+ "math/rand"
+ "time"
+
+ "go-stress-testing/model"
+)
+
+// 接口加权压测
+type ReqListWeigh struct {
+ list []Req
+ weighCount uint32 // 总权重
+}
+
+type Req struct {
+ req *model.Request // 请求信息
+ weights uint32 // 权重,数字越大访问频率越高
+}
+
+func (r *ReqListWeigh) setWeighCount() {
+ r.weighCount = 0
+ for _, value := range r.list {
+ r.weighCount = r.weighCount + value.weights
+ }
+}
+
+var (
+ clientWeigh *ReqListWeigh
+ r *rand.Rand
+)
+
+// 多接口压测示例
+func init() {
+
+ // TODO::压测多个接口示例
+ // 需要压测的接口参数
+ clients := make([]Req, 0)
+ clients = append(clients, Req{req: &model.Request{
+ Url: "https://page.aliyun.com/delivery/plan/list", // 请求url
+ Form: "http", // 请求方式 示例参数:http/webSocket/tcp
+ Method: "POST", // 请求方法 示例参数:GET/POST/PUT
+ Headers: map[string]string{
+ "referer": "https://cn.aliyun.com/",
+ "cookie": "aliyun_choice=CN; JSESSIONID=J8866281-CKCFJ4BUZ7GDO9V89YBW1-KJ3J5V9K-GYUW7; maliyun_temporary_console0=1AbLByOMHeZe3G41KYd5WWZvrM%2BGErkaLcWfBbgveKA9ifboArprPASvFUUfhwHtt44qsDwVqMk8Wkdr1F5LccYk2mPCZJiXb0q%2Bllj5u3SQGQurtyPqnG489y%2FkoA%2FEvOwsXJTvXTFQPK%2BGJD4FJg%3D%3D; cna=L3Q5F8cHDGgCAXL3r8fEZtdU; isg=BFNThsmSCcgX-sUcc5Jo2s2T4tF9COfKYi8g9wVwr3KphHMmjdh3GrHFvPTqJD_C; l=eBaceXLnQGBjstRJBOfwPurza77OSIRAguPzaNbMiT5POw1B5WAlWZbqyNY6C3GVh6lwR37EODnaBeYBc3K-nxvOu9eFfGMmn",
+ }, // headers 头信息
+ Body: "adPlanQueryParam=%7B%22adZone%22%3A%7B%22positionList%22%3A%5B%7B%22positionId%22%3A83%7D%5D%7D%2C%22requestId%22%3A%2217958651-f205-44c7-ad5d-f8af92a6217a%22%7D", // 消息体
+ Verify: "statusCode", // 验证的方法 示例参数:statusCode、json
+ Timeout: 30 * time.Second, // 是否开启Debug模式
+ Debug: false, // 是否开启Debug模式
+ }, weights: 2})
+
+ clients = append(clients, Req{req: &model.Request{
+ Url: "https://page.aliyun.com/delivery/plan/list", // 请求url
+ Form: "http", // 请求方式 示例参数:http/webSocket/tcp
+ Method: "POST", // 请求方法 示例参数:GET/POST/PUT
+ Headers: map[string]string{
+ "referer": "https://cn.aliyun.com/",
+ "cookie": "aliyun_choice=CN; JSESSIONID=J8866281-CKCFJ4BUZ7GDO9V89YBW1-KJ3J5V9K-GYUW7; maliyun_temporary_console0=1AbLByOMHeZe3G41KYd5WWZvrM%2BGErkaLcWfBbgveKA9ifboArprPASvFUUfhwHtt44qsDwVqMk8Wkdr1F5LccYk2mPCZJiXb0q%2Bllj5u3SQGQurtyPqnG489y%2FkoA%2FEvOwsXJTvXTFQPK%2BGJD4FJg%3D%3D; cna=L3Q5F8cHDGgCAXL3r8fEZtdU; isg=BFNThsmSCcgX-sUcc5Jo2s2T4tF9COfKYi8g9wVwr3KphHMmjdh3GrHFvPTqJD_C; l=eBaceXLnQGBjstRJBOfwPurza77OSIRAguPzaNbMiT5POw1B5WAlWZbqyNY6C3GVh6lwR37EODnaBeYBc3K-nxvOu9eFfGMmn",
+ }, // headers 头信息
+ Body: "adPlanQueryParam=%7B%22adZone%22%3A%7B%22positionList%22%3A%5B%7B%22positionId%22%3A83%7D%5D%7D%2C%22requestId%22%3A%2217958651-f205-44c7-ad5d-f8af92a6217a%22%7D", // 消息体
+ Verify: "statusCode", // 验证的方法 示例参数:statusCode、json
+ Timeout: 30 * time.Second, // 是否开启Debug模式
+ Debug: false, // 是否开启Debug模式
+ }, weights: 1})
+
+ r = rand.New(rand.NewSource(time.Now().Unix()))
+
+ clientWeigh = &ReqListWeigh{
+ list: clients,
+ }
+
+ // TODO::注释下面一行代码
+ clientWeigh.list = nil
+
+ clientWeigh.setWeighCount()
+}
+
+func getRequest(request *model.Request) *model.Request {
+
+ if clientWeigh == nil || clientWeigh.weighCount <= 0 {
+
+ return request
+ }
+
+ n := uint32(r.Int31n(int32(clientWeigh.weighCount)))
+
+ var (
+ count uint32
+ )
+
+ for _, value := range clientWeigh.list {
+ if count >= n {
+ // value.req.Print()
+ return value.req
+ }
+ count = count + value.weights
+ }
+
+ panic("getRequest err")
+
+ return nil
+}
diff --git a/server/golink/websocket_link.go b/server/golink/websocket_link.go
index 0a44cfb..5b58c7c 100644
--- a/server/golink/websocket_link.go
+++ b/server/golink/websocket_link.go
@@ -9,11 +9,12 @@ package golink
import (
"fmt"
+ "sync"
+ "time"
+
"go-stress-testing/heper"
"go-stress-testing/model"
"go-stress-testing/server/client"
- "sync"
- "time"
)
const (
@@ -100,7 +101,7 @@ func webSocketRequest(chanId uint64, ch chan<- *model.RequestResults, i uint64,
fmt.Println("读取数据 失败~")
} else {
// fmt.Println(msg)
- errCode, isSucceed = request.VerifyWebSocket(request, seq, msg)
+ errCode, isSucceed = request.GetVerifyWebSocket()(request, seq, msg)
}
}
diff --git a/tests/servers.go b/tests/servers.go
new file mode 100644
index 0000000..61578c9
--- /dev/null
+++ b/tests/servers.go
@@ -0,0 +1,39 @@
+/**
+* Created by GoLand.
+* User: link1st
+* Date: 2020/8/1
+* Time: 09:27
+ */
+
+package main
+
+import (
+ "log"
+ "net/http"
+ "runtime"
+)
+
+const (
+ httpPort = "8088"
+)
+
+func main() {
+
+ runtime.GOMAXPROCS(runtime.NumCPU() - 1)
+
+ hello := func(w http.ResponseWriter, req *http.Request) {
+ data := "Hello, go-stress-testing! \n"
+
+ w.Header().Add("Server", "golang")
+ w.Write([]byte(data))
+
+ return
+ }
+
+ http.HandleFunc("/", hello)
+ err := http.ListenAndServe(":"+httpPort, nil)
+
+ if err != nil {
+ log.Fatal("ListenAndServe: ", err)
+ }
+}
From ab0ca6d0b53fc572fde4800bb2867d14799e16d2 Mon Sep 17 00:00:00 2001
From: lizhuo200701
Date: Fri, 14 Aug 2020 10:42:26 +0800
Subject: [PATCH 46/75] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dheader=20=E4=B8=AD?=
=?UTF-8?q?=E8=AE=BE=E7=BD=AEHost=20=E4=B8=8D=E7=94=9F=E6=95=88=E9=97=AE?=
=?UTF-8?q?=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
server/client/http_client.go | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/server/client/http_client.go b/server/client/http_client.go
index de4f3e8..afa0e7b 100644
--- a/server/client/http_client.go
+++ b/server/client/http_client.go
@@ -39,7 +39,10 @@ func HttpRequest(method, url string, body io.Reader, headers map[string]string,
return
}
-
+ // 在req中设置Host,解决在header中设置Host不生效问题
+ if _, ok := headers["Host"]; ok {
+ req.Host = headers["Host"]
+ }
// 设置默认为utf-8编码
if _, ok := headers["Content-Type"]; !ok {
if headers == nil {
From 3f10a27eb941d6a8ed2596570ed0b6c4ca9f7a87 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Sat, 12 Sep 2020 19:30:26 +0800
Subject: [PATCH 47/75] =?UTF-8?q?=E6=80=A7=E8=83=BD=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
heper/heper.go | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/heper/heper.go b/heper/heper.go
index fe4f626..19d30dd 100644
--- a/heper/heper.go
+++ b/heper/heper.go
@@ -13,11 +13,6 @@ import (
// 时间差,纳秒
func DiffNano(startTime time.Time) (diff int64) {
-
- startTimeStamp := startTime.UnixNano()
- endTimeStamp := time.Now().UnixNano()
-
- diff = endTimeStamp - startTimeStamp
-
+ diff = int64(time.Since(startTime))
return
}
From 0c63b11507e34d331ac9c4d8f90e6d801d8e562c Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Sun, 13 Sep 2020 11:40:01 +0800
Subject: [PATCH 48/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index de4c22e..376c1ab 100644
--- a/README.md
+++ b/README.md
@@ -611,6 +611,7 @@ func main() {
- 压测结果
+- [压测结果 示例](https://github.com/link1st/go-stress-testing/issues/32)
| 并发数 | go_stress_testing QPS |
| :----: | :----: |
@@ -622,7 +623,6 @@ func main() {
| 50 | 19922.56 |
| 80 | 19155.33 |
| 100 | 18336.46 |
-| 200 | 16813.86 |
从压测的结果上看:效果还不错,压测QPS有接近2W
From 486201f27cc61f3b11d1dc6558d7c6d7e33c9881 Mon Sep 17 00:00:00 2001
From: Link <562117637@qq.com>
Date: Mon, 28 Sep 2020 14:32:12 +0800
Subject: [PATCH 49/75] Create statistics_test.go
---
server/statistics/statistics_test.go | 36 ++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 server/statistics/statistics_test.go
diff --git a/server/statistics/statistics_test.go b/server/statistics/statistics_test.go
new file mode 100644
index 0000000..6a60833
--- /dev/null
+++ b/server/statistics/statistics_test.go
@@ -0,0 +1,36 @@
+/**
+* Package statistics
+*
+* User: link1st
+* Date: 2020/9/28
+* Time: 14:02
+ */
+
+package statistics
+
+import (
+ "reflect"
+ "testing"
+)
+
+// TestPrintMap
+func TestPrintMap(t *testing.T) {
+
+ tt := map[string]struct {
+ a map[int]int
+ result string
+ }{
+ "test1": {a: map[int]int{
+ 200: 50,
+ 500: 10,
+ 100: 20,
+ }, result: "100:20;200:50;500:10"},
+ }
+
+ for _, value := range tt {
+ str := printMap(value.a)
+ if !reflect.DeepEqual(value.result, str) {
+ t.Errorf("数据不一致 预期:%v 实际:%v", value.result, str)
+ }
+ }
+}
From 1b7e9ea0a9eef69bfc3fb554a015f6037be1c62c Mon Sep 17 00:00:00 2001
From: Link <562117637@qq.com>
Date: Mon, 28 Sep 2020 14:32:41 +0800
Subject: [PATCH 50/75] add sort
---
server/statistics/statistics.go | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/server/statistics/statistics.go b/server/statistics/statistics.go
index efaaf3a..5a89554 100644
--- a/server/statistics/statistics.go
+++ b/server/statistics/statistics.go
@@ -9,10 +9,12 @@ package statistics
import (
"fmt"
- "go-stress-testing/model"
+ "sort"
"strings"
"sync"
"time"
+
+ "go-stress-testing/model"
)
var (
@@ -192,6 +194,8 @@ func printMap(errCode map[int]int) (mapStr string) {
mapArr = append(mapArr, fmt.Sprintf("%d:%d", key, value))
}
+ sort.Strings(mapArr)
+
mapStr = strings.Join(mapArr, ";")
return
From ded88511e90f07e24832087baf38cb1d88198005 Mon Sep 17 00:00:00 2001
From: Link <562117637@qq.com>
Date: Wed, 21 Oct 2020 20:38:13 +0800
Subject: [PATCH 51/75] =?UTF-8?q?fix=20=E5=B9=B3=E5=9D=87=E8=80=97?=
=?UTF-8?q?=E6=97=B6=E7=94=B1=E6=9C=8D=E5=8A=A1=E5=99=A8=E5=B9=B3=E5=9D=87?=
=?UTF-8?q?=E8=80=97=E6=97=B6=E4=BF=AE=E6=94=B9=E4=B8=BA=E5=AE=A2=E6=88=B7?=
=?UTF-8?q?=E7=AB=AF=E5=B9=B3=E5=9D=87=E8=AF=B7=E6=B1=82=E6=97=B6=E9=97=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
server/statistics/statistics.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/server/statistics/statistics.go b/server/statistics/statistics.go
index 5a89554..e86d765 100644
--- a/server/statistics/statistics.go
+++ b/server/statistics/statistics.go
@@ -147,7 +147,7 @@ func calculateData(concurrent, processingTime, requestTime, maxTime, minTime, su
// 平均时长 总耗时/总请求数/并发数 纳秒=>毫秒
if successNum != 0 && concurrent != 0 {
- averageTime = float64(processingTime) / float64(successNum*1e6*concurrent)
+ averageTime = float64(processingTime) / float64(successNum*1e6)
}
// 纳秒=>毫秒
From 0beab0abacb22b35a941eda84deb2999de73f844 Mon Sep 17 00:00:00 2001
From: wuhelong
Date: Fri, 30 Oct 2020 10:09:25 +0800
Subject: [PATCH 52/75] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E4=BC=A0=E8=BE=93=E5=B9=B6=E8=AE=B0=E5=BD=95=E4=B8=8B=E8=BD=BD?=
=?UTF-8?q?=E6=95=B0=E6=8D=AE=E9=87=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
go.mod | 5 +++-
go.sum | 1 +
model/request_model.go | 46 ++++++++++++++++-----------------
server/client/http_client.go | 7 +++--
server/golink/http_link.go | 36 +++++++++++++++++++-------
server/statistics/statistics.go | 29 ++++++++++++++-------
6 files changed, 79 insertions(+), 45 deletions(-)
diff --git a/go.mod b/go.mod
index d9021ef..4a8c992 100644
--- a/go.mod
+++ b/go.mod
@@ -2,4 +2,7 @@ module go-stress-testing
go 1.14
-require golang.org/x/net v0.0.0-20190724013045-ca1201d0de80
+require (
+ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80
+ golang.org/x/text v0.3.0
+)
diff --git a/go.sum b/go.sum
index c037375..bc41edb 100644
--- a/go.sum
+++ b/go.sum
@@ -2,4 +2,5 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/model/request_model.go b/model/request_model.go
index e4c5ce9..7b2a197 100644
--- a/model/request_model.go
+++ b/model/request_model.go
@@ -66,14 +66,14 @@ type VerifyWebSocket func(request *Request, seq string, msg []byte) (code int, i
// 请求结果
type Request struct {
- Url string // Url
- Form string // http/webSocket/tcp
- Method string // 方法 GET/POST/PUT
- Headers map[string]string // Headers
- Body string // body
- Verify string // 验证的方法
- Timeout time.Duration // 请求超时时间
- Debug bool // 是否开启Debug模式
+ Url string // Url
+ Form string // http/webSocket/tcp
+ Method string // 方法 GET/POST/PUT
+ Headers map[string]string // Headers
+ Body string // body
+ Verify string // 验证的方法
+ Timeout time.Duration // 请求超时时间
+ Debug bool // 是否开启Debug模式
// 连接以后初始化事件
// 循环事件 切片 时间 动作
@@ -169,7 +169,7 @@ func NewRequest(url string, verify string, timeout time.Duration, debug bool, pa
}
var (
- ok bool
+ ok bool
)
switch form {
@@ -207,14 +207,14 @@ func NewRequest(url string, verify string, timeout time.Duration, debug bool, pa
}
request = &Request{
- Url: url,
- Form: form,
- Method: strings.ToUpper(method),
- Headers: headers,
- Body: body,
- Verify: verify,
- Timeout: timeout,
- Debug: debug,
+ Url: url,
+ Form: form,
+ Method: strings.ToUpper(method),
+ Headers: headers,
+ Body: body,
+ Verify: verify,
+ Timeout: timeout,
+ Debug: debug,
}
return
@@ -272,17 +272,17 @@ func (r *Request) IsParameterLegal() (err error) {
return errors.New("验证器不存在:" + key)
}
-
return
}
// 请求结果
type RequestResults struct {
- Id string // 消息Id
- ChanId uint64 // 消息Id
- Time uint64 // 请求时间 纳秒
- IsSucceed bool // 是否请求成功
- ErrCode int // 错误码
+ Id string // 消息Id
+ ChanId uint64 // 消息Id
+ Time uint64 // 请求时间 纳秒
+ IsSucceed bool // 是否请求成功
+ ErrCode int // 错误码
+ ReceivedBytes int64
}
func (r *RequestResults) SetId(chanId uint64, number uint64) {
diff --git a/server/client/http_client.go b/server/client/http_client.go
index afa0e7b..75445fd 100644
--- a/server/client/http_client.go
+++ b/server/client/http_client.go
@@ -9,13 +9,16 @@ package client
import (
"crypto/tls"
- "fmt"
"go-stress-testing/heper"
"io"
+ "log"
"net/http"
+ "os"
"time"
)
+var logErr = log.New(os.Stderr, "", 0)
+
// HTTP 请求
// method 方法 GET POST
// url 请求的url
@@ -59,7 +62,7 @@ func HttpRequest(method, url string, body io.Reader, headers map[string]string,
resp, err = client.Do(req)
requestTime = uint64(heper.DiffNano(startTime))
if err != nil {
- fmt.Println("请求失败:", err)
+ logErr.Println("请求失败:", err)
return
}
diff --git a/server/golink/http_link.go b/server/golink/http_link.go
index d922576..d9eb8fd 100644
--- a/server/golink/http_link.go
+++ b/server/golink/http_link.go
@@ -14,6 +14,8 @@ import (
"go-stress-testing/server/client"
)
+var buf = make([]byte, 1024*1024)
+
// http go link
func Http(chanId uint64, ch chan<- *model.RequestResults, totalNumber uint64, wg *sync.WaitGroup, request *model.Request) {
@@ -26,12 +28,13 @@ func Http(chanId uint64, ch chan<- *model.RequestResults, totalNumber uint64, wg
list := getRequestList(request)
- isSucceed, errCode, requestTime := sendList(list)
+ isSucceed, errCode, requestTime, contentLength := sendList(list)
requestResults := &model.RequestResults{
- Time: requestTime,
- IsSucceed: isSucceed,
- ErrCode: errCode,
+ Time: requestTime,
+ IsSucceed: isSucceed,
+ ErrCode: errCode,
+ ReceivedBytes: contentLength,
}
requestResults.SetId(chanId, i)
@@ -41,15 +44,17 @@ func Http(chanId uint64, ch chan<- *model.RequestResults, totalNumber uint64, wg
return
}
+
// 多个接口分步压测
-func sendList(requestList []*model.Request) (isSucceed bool, errCode int, requestTime uint64) {
+func sendList(requestList []*model.Request) (isSucceed bool, errCode int, requestTime uint64, contentLength int64) {
errCode = model.HttpOk
for _, request := range requestList {
- succeed, code, u := send(request)
+ succeed, code, u, length := send(request)
isSucceed = succeed
errCode = code
requestTime = requestTime + u
+ contentLength = contentLength + length
if succeed == false {
break
@@ -60,11 +65,12 @@ func sendList(requestList []*model.Request) (isSucceed bool, errCode int, reques
}
// send 发送一次请求
-func send(request *model.Request) (bool, int, uint64) {
+func send(request *model.Request) (bool, int, uint64, int64) {
var (
// startTime = time.Now()
- isSucceed = false
- errCode = model.HttpOk
+ isSucceed = false
+ errCode = model.HttpOk
+ contentLength = int64(0)
)
newRequest := getRequest(request)
@@ -75,8 +81,18 @@ func send(request *model.Request) (bool, int, uint64) {
if err != nil {
errCode = model.RequestErr // 请求错误
} else {
+
+ contentLength = 0
+ for {
+ n, err := resp.Body.Read(buf)
+ contentLength += int64(n)
+ if err != nil {
+ break
+ }
+ }
+
// 验证请求是否成功
errCode, isSucceed = newRequest.GetVerifyHttp()(newRequest, resp)
}
- return isSucceed, errCode, requestTime
+ return isSucceed, errCode, requestTime, contentLength
}
diff --git a/server/statistics/statistics.go b/server/statistics/statistics.go
index e86d765..ac9dca4 100644
--- a/server/statistics/statistics.go
+++ b/server/statistics/statistics.go
@@ -15,11 +15,15 @@ import (
"time"
"go-stress-testing/model"
+
+ "golang.org/x/text/language"
+ "golang.org/x/text/message"
)
var (
// 输出统计数据的时间
exportStatisticsTime = 1 * time.Second
+ p = message.NewPrinter(language.English)
)
// 接收结果并处理
@@ -45,6 +49,7 @@ func ReceivingResults(concurrent uint64, ch <-chan *model.RequestResults, wg *sy
failureNum uint64 // 处理失败数,code不为0
chanIdLen int // 并发数
chanIds = make(map[uint64]bool)
+ receivedBytes int64
)
statTime := uint64(time.Now().UnixNano())
@@ -60,7 +65,7 @@ func ReceivingResults(concurrent uint64, ch <-chan *model.RequestResults, wg *sy
case <-ticker.C:
endTime := uint64(time.Now().UnixNano())
requestTime = endTime - statTime
- go calculateData(concurrent, processingTime, requestTime, maxTime, minTime, successNum, failureNum, chanIdLen, errCode)
+ go calculateData(concurrent, processingTime, requestTime, maxTime, minTime, successNum, failureNum, chanIdLen, errCode, receivedBytes)
case <-stopChan:
// 处理完成
@@ -99,6 +104,8 @@ func ReceivingResults(concurrent uint64, ch <-chan *model.RequestResults, wg *sy
errCode[data.ErrCode] = 1
}
+ receivedBytes += data.ReceivedBytes
+
if _, ok := chanIds[data.ChanId]; !ok {
chanIds[data.ChanId] = true
chanIdLen = len(chanIds)
@@ -111,7 +118,7 @@ func ReceivingResults(concurrent uint64, ch <-chan *model.RequestResults, wg *sy
endTime := uint64(time.Now().UnixNano())
requestTime = endTime - statTime
- calculateData(concurrent, processingTime, requestTime, maxTime, minTime, successNum, failureNum, chanIdLen, errCode)
+ calculateData(concurrent, processingTime, requestTime, maxTime, minTime, successNum, failureNum, chanIdLen, errCode, receivedBytes)
fmt.Printf("\n\n")
@@ -127,7 +134,7 @@ func ReceivingResults(concurrent uint64, ch <-chan *model.RequestResults, wg *sy
}
// 计算数据
-func calculateData(concurrent, processingTime, requestTime, maxTime, minTime, successNum, failureNum uint64, chanIdLen int, errCode map[int]int) {
+func calculateData(concurrent, processingTime, requestTime, maxTime, minTime, successNum, failureNum uint64, chanIdLen int, errCode map[int]int, receivedBytes int64) {
if processingTime == 0 {
processingTime = 1
}
@@ -158,27 +165,31 @@ func calculateData(concurrent, processingTime, requestTime, maxTime, minTime, su
// 打印的时长都为毫秒
// result := fmt.Sprintf("请求总数:%8d|successNum:%8d|failureNum:%8d|qps:%9.3f|maxTime:%9.3f|minTime:%9.3f|平均时长:%9.3f|errCode:%v", successNum+failureNum, successNum, failureNum, qps, maxTimeFloat, minTimeFloat, averageTime, errCode)
// fmt.Println(result)
- table(successNum, failureNum, errCode, qps, averageTime, maxTimeFloat, minTimeFloat, requestTimeFloat, chanIdLen)
+ table(successNum, failureNum, errCode, qps, averageTime, maxTimeFloat, minTimeFloat, requestTimeFloat, chanIdLen, receivedBytes)
}
// 打印表头信息
func header() {
fmt.Printf("\n\n")
// 打印的时长都为毫秒 总请数
- fmt.Println("─────┬───────┬───────┬───────┬────────┬────────┬────────┬────────┬────────")
- result := fmt.Sprintf(" 耗时│ 并发数│ 成功数│ 失败数│ qps │最长耗时│最短耗时│平均耗时│ 错误码")
+ fmt.Println("─────┬───────┬───────┬───────┬────────┬────────┬────────┬────────┬────────┬────────┬────────")
+ result := fmt.Sprintf(" 耗时│ 并发数│ 成功数│ 失败数│ qps │最长耗时│最短耗时│平均耗时│下载字节│字节每秒│ 错误码")
fmt.Println(result)
// result = fmt.Sprintf("耗时(s) │总请求数│成功数│失败数│QPS│最长耗时│最短耗时│平均耗时│错误码")
// fmt.Println(result)
- fmt.Println("─────┼───────┼───────┼───────┼────────┼────────┼────────┼────────┼────────")
+ fmt.Println("─────┼───────┼───────┼───────┼────────┼────────┼────────┼────────┼────────┼────────┼────────")
return
}
// 打印表格
-func table(successNum, failureNum uint64, errCode map[int]int, qps, averageTime, maxTimeFloat, minTimeFloat, requestTimeFloat float64, chanIdLen int) {
+func table(successNum, failureNum uint64, errCode map[int]int, qps, averageTime, maxTimeFloat, minTimeFloat, requestTimeFloat float64, chanIdLen int, receivedBytes int64) {
// 打印的时长都为毫秒
- result := fmt.Sprintf("%4.0fs│%7d│%7d│%7d│%8.2f│%8.2f│%8.2f│%8.2f│%v", requestTimeFloat, chanIdLen, successNum, failureNum, qps, maxTimeFloat, minTimeFloat, averageTime, printMap(errCode))
+ result := fmt.Sprintf("%4.0fs│%7d│%7d│%7d│%8.2f│%8.2f│%8.2f│%8.2f│%8s|%8s│%v",
+ requestTimeFloat, chanIdLen, successNum, failureNum, qps, maxTimeFloat, minTimeFloat, averageTime,
+ p.Sprintf("%d", receivedBytes),
+ p.Sprintf("%d", receivedBytes/int64(requestTimeFloat)),
+ printMap(errCode))
fmt.Println(result)
return
From 39b7f2cb7b08e1c2d7f2232e9316932f9175f9fe Mon Sep 17 00:00:00 2001
From: gongzhihong
Date: Fri, 13 Nov 2020 17:57:59 +0800
Subject: [PATCH 53/75] .gitignore add vendor
---
.gitignore | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index 2f4c6ac..0ff29f2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,4 +19,5 @@ go-stress-testing-linux
go-stress-testing-win.exe
model/modeltest/*
model/modeltest*
-server.go
\ No newline at end of file
+server.go
+vendor
\ No newline at end of file
From 7067b6917ed9e141b52278eac456a5e827cbb1a0 Mon Sep 17 00:00:00 2001
From: gongzhihong
Date: Fri, 13 Nov 2020 18:10:55 +0800
Subject: [PATCH 54/75] =?UTF-8?q?=E9=87=8D=E6=96=B0=E8=B5=8B=E5=80=BC?=
=?UTF-8?q?=E5=9C=A8resp.body=20read=E4=B9=8B=E5=90=8E?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
server/golink/http_link.go | 3 +++
server/verify/http_verify.go | 4 ++--
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/server/golink/http_link.go b/server/golink/http_link.go
index d9eb8fd..4fe2c36 100644
--- a/server/golink/http_link.go
+++ b/server/golink/http_link.go
@@ -8,6 +8,8 @@
package golink
import (
+ "bytes"
+ "io/ioutil"
"sync"
"go-stress-testing/model"
@@ -85,6 +87,7 @@ func send(request *model.Request) (bool, int, uint64, int64) {
contentLength = 0
for {
n, err := resp.Body.Read(buf)
+ resp.Body = ioutil.NopCloser(bytes.NewReader(buf))
contentLength += int64(n)
if err != nil {
break
diff --git a/server/verify/http_verify.go b/server/verify/http_verify.go
index 8d29b23..d3ba561 100644
--- a/server/verify/http_verify.go
+++ b/server/verify/http_verify.go
@@ -8,6 +8,7 @@
package verify
import (
+ "bytes"
"compress/gzip"
"encoding/json"
"fmt"
@@ -29,9 +30,8 @@ func getZipData(response *http.Response) (body []byte, err error) {
default:
reader = response.Body
}
-
body, err = ioutil.ReadAll(reader)
-
+ response.Body = ioutil.NopCloser(bytes.NewReader(body))
return
}
From ee43255ba5689a4eaac5faad97f99f856d45c9a1 Mon Sep 17 00:00:00 2001
From: Link <562117637@qq.com>
Date: Fri, 20 Nov 2020 21:03:29 +0800
Subject: [PATCH 55/75] fix bug Divisor is not zero
https://github.com/link1st/go-stress-testing/issues/40
---
server/statistics/statistics.go | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/server/statistics/statistics.go b/server/statistics/statistics.go
index ac9dca4..d490a74 100644
--- a/server/statistics/statistics.go
+++ b/server/statistics/statistics.go
@@ -184,11 +184,17 @@ func header() {
// 打印表格
func table(successNum, failureNum uint64, errCode map[int]int, qps, averageTime, maxTimeFloat, minTimeFloat, requestTimeFloat float64, chanIdLen int, receivedBytes int64) {
+ var (
+ speed int64
+ )
+ if requestTimeFloat > 0 {
+ speed = receivedBytes / int64(requestTimeFloat)
+ }
// 打印的时长都为毫秒
result := fmt.Sprintf("%4.0fs│%7d│%7d│%7d│%8.2f│%8.2f│%8.2f│%8.2f│%8s|%8s│%v",
requestTimeFloat, chanIdLen, successNum, failureNum, qps, maxTimeFloat, minTimeFloat, averageTime,
p.Sprintf("%d", receivedBytes),
- p.Sprintf("%d", receivedBytes/int64(requestTimeFloat)),
+ p.Sprintf("%d", speed),
printMap(errCode))
fmt.Println(result)
From 478ffc6cedf9ae038d9dbeac6f13c8da8509f418 Mon Sep 17 00:00:00 2001
From: sishui
Date: Tue, 24 Nov 2020 12:35:15 +0800
Subject: [PATCH 56/75] fix requestTimeFloat integer divide by zero
---
server/statistics/statistics.go | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/server/statistics/statistics.go b/server/statistics/statistics.go
index d490a74..977cc9d 100644
--- a/server/statistics/statistics.go
+++ b/server/statistics/statistics.go
@@ -184,17 +184,11 @@ func header() {
// 打印表格
func table(successNum, failureNum uint64, errCode map[int]int, qps, averageTime, maxTimeFloat, minTimeFloat, requestTimeFloat float64, chanIdLen int, receivedBytes int64) {
- var (
- speed int64
- )
- if requestTimeFloat > 0 {
- speed = receivedBytes / int64(requestTimeFloat)
- }
// 打印的时长都为毫秒
result := fmt.Sprintf("%4.0fs│%7d│%7d│%7d│%8.2f│%8.2f│%8.2f│%8.2f│%8s|%8s│%v",
requestTimeFloat, chanIdLen, successNum, failureNum, qps, maxTimeFloat, minTimeFloat, averageTime,
p.Sprintf("%d", receivedBytes),
- p.Sprintf("%d", speed),
+ p.Sprintf("%d", int64(float64(receivedBytes)/requestTimeFloat)),
printMap(errCode))
fmt.Println(result)
From 83a9e8a2e9d0c5eaae885177ebdb4d853a9ca6c0 Mon Sep 17 00:00:00 2001
From: Link <562117637@qq.com>
Date: Tue, 24 Nov 2020 15:35:00 +0800
Subject: [PATCH 57/75] Update README.md
---
README.md | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 376c1ab..d4125f8 100644
--- a/README.md
+++ b/README.md
@@ -319,7 +319,7 @@ pip3 install websocket-client
编写压测脚本 **test.py**
```python
-from locust import HttpLocust, TaskSet, task
+from locust import HttpUser, TaskSet, task
# 定义用户行为
class UserBehavior(TaskSet):
@@ -328,9 +328,8 @@ class UserBehavior(TaskSet):
def baidu_index(self):
self.client.get("/")
-
-class WebsiteUser(HttpLocust):
- task_set = UserBehavior # 指向一个定义的用户行为类
+class WebsiteUser(HttpUser):
+ task = [UserBehavior] # 指向一个定义的用户行为类
min_wait = 3000 # 执行事务之间用户等待时间的下界(单位:毫秒)
max_wait = 6000 # 执行事务之间用户等待时间的上界(单位:毫秒)
```
From 2855acc096b64868a987017e556cb5dc7ca476a0 Mon Sep 17 00:00:00 2001
From: sishui
Date: Tue, 24 Nov 2020 17:00:58 +0800
Subject: [PATCH 58/75] =?UTF-8?q?=E5=85=BC=E5=AE=B9=20requestTimeFloat=20?=
=?UTF-8?q?=E6=9C=89=E6=A6=82=E7=8E=87=E4=B8=BA0=E7=9A=84=E6=83=85?=
=?UTF-8?q?=E5=86=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
server/statistics/statistics.go | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/server/statistics/statistics.go b/server/statistics/statistics.go
index 977cc9d..042fc69 100644
--- a/server/statistics/statistics.go
+++ b/server/statistics/statistics.go
@@ -184,11 +184,20 @@ func header() {
// 打印表格
func table(successNum, failureNum uint64, errCode map[int]int, qps, averageTime, maxTimeFloat, minTimeFloat, requestTimeFloat float64, chanIdLen int, receivedBytes int64) {
+ var (
+ speed int64
+ )
+ requestTimeFloat = 0.0
+ if requestTimeFloat > 0 {
+ speed = int64(float64(receivedBytes)/requestTimeFloat)
+ }else{
+ speed = 0
+ }
// 打印的时长都为毫秒
result := fmt.Sprintf("%4.0fs│%7d│%7d│%7d│%8.2f│%8.2f│%8.2f│%8.2f│%8s|%8s│%v",
requestTimeFloat, chanIdLen, successNum, failureNum, qps, maxTimeFloat, minTimeFloat, averageTime,
p.Sprintf("%d", receivedBytes),
- p.Sprintf("%d", int64(float64(receivedBytes)/requestTimeFloat)),
+ p.Sprintf("%d", speed),
printMap(errCode))
fmt.Println(result)
From 135e65007c9df88ba97bc4ad56926bf0aabf737b Mon Sep 17 00:00:00 2001
From: sishui
Date: Tue, 24 Nov 2020 17:02:42 +0800
Subject: [PATCH 59/75] =?UTF-8?q?=E5=85=BC=E5=AE=B9=20requestTimeFloat=20?=
=?UTF-8?q?=E5=8F=AF=E8=83=BD=E4=B8=BA=200=20=E7=9A=84=E6=83=85=E5=86=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
server/statistics/statistics.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/server/statistics/statistics.go b/server/statistics/statistics.go
index 042fc69..36880d5 100644
--- a/server/statistics/statistics.go
+++ b/server/statistics/statistics.go
@@ -187,10 +187,10 @@ func table(successNum, failureNum uint64, errCode map[int]int, qps, averageTime,
var (
speed int64
)
- requestTimeFloat = 0.0
+
if requestTimeFloat > 0 {
- speed = int64(float64(receivedBytes)/requestTimeFloat)
- }else{
+ speed = int64(float64(receivedBytes) / requestTimeFloat)
+ } else {
speed = 0
}
// 打印的时长都为毫秒
From e29aacf0157fa267a862833937a2eb2728392ba6 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Sat, 30 Jan 2021 19:10:26 +0800
Subject: [PATCH 60/75] =?UTF-8?q?fix=20bug=20=E7=BD=91=E9=A1=B5=E8=BF=9B?=
=?UTF-8?q?=E8=A1=8C=20gzip=20=E5=8E=8B=E7=BC=A9=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
server/golink/http_link.go | 15 +--------------
server/statistics/statistics.go | 16 ++++++++++++++--
2 files changed, 15 insertions(+), 16 deletions(-)
diff --git a/server/golink/http_link.go b/server/golink/http_link.go
index 4fe2c36..b4a4407 100644
--- a/server/golink/http_link.go
+++ b/server/golink/http_link.go
@@ -8,16 +8,12 @@
package golink
import (
- "bytes"
- "io/ioutil"
"sync"
"go-stress-testing/model"
"go-stress-testing/server/client"
)
-var buf = make([]byte, 1024*1024)
-
// http go link
func Http(chanId uint64, ch chan<- *model.RequestResults, totalNumber uint64, wg *sync.WaitGroup, request *model.Request) {
@@ -83,16 +79,7 @@ func send(request *model.Request) (bool, int, uint64, int64) {
if err != nil {
errCode = model.RequestErr // 请求错误
} else {
-
- contentLength = 0
- for {
- n, err := resp.Body.Read(buf)
- resp.Body = ioutil.NopCloser(bytes.NewReader(buf))
- contentLength += int64(n)
- if err != nil {
- break
- }
- }
+ contentLength = resp.ContentLength
// 验证请求是否成功
errCode, isSucceed = newRequest.GetVerifyHttp()(newRequest, resp)
diff --git a/server/statistics/statistics.go b/server/statistics/statistics.go
index 36880d5..68fd8f9 100644
--- a/server/statistics/statistics.go
+++ b/server/statistics/statistics.go
@@ -193,11 +193,23 @@ func table(successNum, failureNum uint64, errCode map[int]int, qps, averageTime,
} else {
speed = 0
}
+ var (
+ receivedBytesStr string
+ speedStr string
+ )
+ // 判断获取下载字节长度是否是未知
+ if receivedBytes == -1 {
+ receivedBytesStr = ""
+ speedStr = ""
+ } else {
+ receivedBytesStr = p.Sprintf("%d", receivedBytes)
+ speedStr = p.Sprintf("%d", speed)
+ }
+
// 打印的时长都为毫秒
result := fmt.Sprintf("%4.0fs│%7d│%7d│%7d│%8.2f│%8.2f│%8.2f│%8.2f│%8s|%8s│%v",
requestTimeFloat, chanIdLen, successNum, failureNum, qps, maxTimeFloat, minTimeFloat, averageTime,
- p.Sprintf("%d", receivedBytes),
- p.Sprintf("%d", speed),
+ receivedBytesStr, speedStr,
printMap(errCode))
fmt.Println(result)
From c2f8730e43166893ea5d30968f2e980730f6407a Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Sat, 30 Jan 2021 19:16:24 +0800
Subject: [PATCH 61/75] =?UTF-8?q?fix=20bug=20=E7=BD=91=E9=A1=B5=E8=BF=9B?=
=?UTF-8?q?=E8=A1=8C=20gzip=20=E5=8E=8B=E7=BC=A9=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
server/statistics/statistics.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/server/statistics/statistics.go b/server/statistics/statistics.go
index 68fd8f9..98869d5 100644
--- a/server/statistics/statistics.go
+++ b/server/statistics/statistics.go
@@ -198,7 +198,7 @@ func table(successNum, failureNum uint64, errCode map[int]int, qps, averageTime,
speedStr string
)
// 判断获取下载字节长度是否是未知
- if receivedBytes == -1 {
+ if receivedBytes <= 0 {
receivedBytesStr = ""
speedStr = ""
} else {
From f2d130578f67edda4f3b217117d3ccb1e5b7925e Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Sat, 30 Jan 2021 23:13:11 +0800
Subject: [PATCH 62/75] add .gitignore
---
.gitignore | 3 ++-
test.sh | 0
2 files changed, 2 insertions(+), 1 deletion(-)
create mode 100644 test.sh
diff --git a/.gitignore b/.gitignore
index 0ff29f2..7c6337f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,4 +20,5 @@ go-stress-testing-win.exe
model/modeltest/*
model/modeltest*
server.go
-vendor
\ No newline at end of file
+vendor
+test.sh
\ No newline at end of file
diff --git a/test.sh b/test.sh
new file mode 100644
index 0000000..e69de29
From 988c16745da7086904c675af88c8e7e42400c1d3 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Sat, 30 Jan 2021 23:17:02 +0800
Subject: [PATCH 63/75] fix
---
curl/{test.post.cur.txt => test.post.curl.txt} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename curl/{test.post.cur.txt => test.post.curl.txt} (100%)
diff --git a/curl/test.post.cur.txt b/curl/test.post.curl.txt
similarity index 100%
rename from curl/test.post.cur.txt
rename to curl/test.post.curl.txt
From 099e116e335e83101e925216255560100eb41acb Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Sat, 30 Jan 2021 23:17:39 +0800
Subject: [PATCH 64/75] fix
---
test.sh | 0
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 test.sh
diff --git a/test.sh b/test.sh
deleted file mode 100644
index e69de29..0000000
From 8e40f78d409a0e57986fec481124bca5870c6e7e Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Sat, 30 Jan 2021 23:36:40 +0800
Subject: [PATCH 65/75] fix
---
server/statistics/statistics.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/server/statistics/statistics.go b/server/statistics/statistics.go
index 98869d5..390cca0 100644
--- a/server/statistics/statistics.go
+++ b/server/statistics/statistics.go
@@ -207,7 +207,7 @@ func table(successNum, failureNum uint64, errCode map[int]int, qps, averageTime,
}
// 打印的时长都为毫秒
- result := fmt.Sprintf("%4.0fs│%7d│%7d│%7d│%8.2f│%8.2f│%8.2f│%8.2f│%8s|%8s│%v",
+ result := fmt.Sprintf("%4.0fs│%7d│%7d│%7d│%8.2f│%8.2f│%8.2f│%8.2f│%8s│%8s│%v",
requestTimeFloat, chanIdLen, successNum, failureNum, qps, maxTimeFloat, minTimeFloat, averageTime,
receivedBytesStr, speedStr,
printMap(errCode))
From 2b4b14aaf026d08276531cf76f42de90efd3bc61 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Thu, 4 Feb 2021 00:49:13 +0800
Subject: [PATCH 66/75] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AF=B9=20grpc=20?=
=?UTF-8?q?=E6=8E=A5=E5=8F=A3=E5=8E=8B=E6=B5=8B=E7=A4=BA=E4=BE=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
go.mod | 2 +
go.sum | 77 ++++++++++++
model/request_model.go | 3 +
proto/pb.pb.go | 229 +++++++++++++++++++++++++++++++++++
proto/pb.proto | 26 ++++
server/client/grpc_client.go | 66 ++++++++++
server/dispose.go | 9 ++
server/golink/grpc_link.go | 79 ++++++++++++
tests/grpc/main.go | 51 ++++++++
9 files changed, 542 insertions(+)
create mode 100644 proto/pb.pb.go
create mode 100644 proto/pb.proto
create mode 100644 server/client/grpc_client.go
create mode 100644 server/golink/grpc_link.go
create mode 100644 tests/grpc/main.go
diff --git a/go.mod b/go.mod
index 4a8c992..6150d8d 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,8 @@ module go-stress-testing
go 1.14
require (
+ github.com/golang/protobuf v1.4.2
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80
golang.org/x/text v0.3.0
+ google.golang.org/grpc v1.35.0
)
diff --git a/go.sum b/go.sum
index bc41edb..ed4a46a 100644
--- a/go.sum
+++ b/go.sum
@@ -1,6 +1,83 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.35.0 h1:TwIQcH3es+MojMVojxxfQ3l3OF2KzlRxML2xZq0kRo8=
+google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/model/request_model.go b/model/request_model.go
index 7b2a197..02aa87a 100644
--- a/model/request_model.go
+++ b/model/request_model.go
@@ -25,6 +25,7 @@ const (
FormTypeHttp = "http"
FormTypeWebSocket = "webSocket"
+ FormTypeGRPC = "grpc"
)
var (
@@ -157,6 +158,8 @@ func NewRequest(url string, verify string, timeout time.Duration, debug bool, pa
form = FormTypeHttp
} else if strings.HasPrefix(url, "ws://") || strings.HasPrefix(url, "wss://") {
form = FormTypeWebSocket
+ } else if strings.HasPrefix(url, "grpc://") || strings.HasPrefix(url, "rpc://") {
+ form = FormTypeGRPC
} else {
form = FormTypeHttp
url = fmt.Sprintf("http://%s", url)
diff --git a/proto/pb.pb.go b/proto/pb.pb.go
new file mode 100644
index 0000000..9d25eae
--- /dev/null
+++ b/proto/pb.pb.go
@@ -0,0 +1,229 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: pb.proto
+
+package protobuf
+
+import (
+ context "context"
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+ math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+// 请求
+type Request struct {
+ // UserName 用户昵称
+ UserName string `protobuf:"bytes,1,opt,name=userName,proto3" json:"userName,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Request) Reset() { *m = Request{} }
+func (m *Request) String() string { return proto.CompactTextString(m) }
+func (*Request) ProtoMessage() {}
+func (*Request) Descriptor() ([]byte, []int) {
+ return fileDescriptor_f80abaa17e25ccc8, []int{0}
+}
+
+func (m *Request) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Request.Unmarshal(m, b)
+}
+func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Request.Marshal(b, m, deterministic)
+}
+func (m *Request) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Request.Merge(m, src)
+}
+func (m *Request) XXX_Size() int {
+ return xxx_messageInfo_Request.Size(m)
+}
+func (m *Request) XXX_DiscardUnknown() {
+ xxx_messageInfo_Request.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Request proto.InternalMessageInfo
+
+func (m *Request) GetUserName() string {
+ if m != nil {
+ return m.UserName
+ }
+ return ""
+}
+
+// 响应
+type Response struct {
+ // 状态码
+ Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
+ // 状态码说明
+ Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"`
+ // Data 返回数据
+ Data string `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Response) Reset() { *m = Response{} }
+func (m *Response) String() string { return proto.CompactTextString(m) }
+func (*Response) ProtoMessage() {}
+func (*Response) Descriptor() ([]byte, []int) {
+ return fileDescriptor_f80abaa17e25ccc8, []int{1}
+}
+
+func (m *Response) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Response.Unmarshal(m, b)
+}
+func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Response.Marshal(b, m, deterministic)
+}
+func (m *Response) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Response.Merge(m, src)
+}
+func (m *Response) XXX_Size() int {
+ return xxx_messageInfo_Response.Size(m)
+}
+func (m *Response) XXX_DiscardUnknown() {
+ xxx_messageInfo_Response.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Response proto.InternalMessageInfo
+
+func (m *Response) GetCode() int32 {
+ if m != nil {
+ return m.Code
+ }
+ return 0
+}
+
+func (m *Response) GetMsg() string {
+ if m != nil {
+ return m.Msg
+ }
+ return ""
+}
+
+func (m *Response) GetData() string {
+ if m != nil {
+ return m.Data
+ }
+ return ""
+}
+
+func init() {
+ proto.RegisterType((*Request)(nil), "protobuf.Request")
+ proto.RegisterType((*Response)(nil), "protobuf.Response")
+}
+
+func init() { proto.RegisterFile("pb.proto", fileDescriptor_f80abaa17e25ccc8) }
+
+var fileDescriptor_f80abaa17e25ccc8 = []byte{
+ // 170 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x28, 0x48, 0xd2, 0x2b,
+ 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x00, 0x53, 0x49, 0xa5, 0x69, 0x4a, 0xaa, 0x5c, 0xec, 0x41,
+ 0xa9, 0x85, 0xa5, 0xa9, 0xc5, 0x25, 0x42, 0x52, 0x5c, 0x1c, 0xa5, 0xc5, 0xa9, 0x45, 0x7e, 0x89,
+ 0xb9, 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x70, 0xbe, 0x92, 0x0b, 0x17, 0x47, 0x50,
+ 0x6a, 0x71, 0x41, 0x7e, 0x5e, 0x71, 0xaa, 0x90, 0x10, 0x17, 0x4b, 0x72, 0x7e, 0x0a, 0x44, 0x0d,
+ 0x6b, 0x10, 0x98, 0x2d, 0x24, 0xc0, 0xc5, 0x9c, 0x5b, 0x9c, 0x2e, 0xc1, 0x04, 0xd6, 0x06, 0x62,
+ 0x82, 0x54, 0xa5, 0x24, 0x96, 0x24, 0x4a, 0x30, 0x83, 0x85, 0xc0, 0x6c, 0x23, 0x27, 0x2e, 0x4e,
+ 0xc7, 0x82, 0xcc, 0xe0, 0xd4, 0xa2, 0xb2, 0xd4, 0x22, 0x21, 0x53, 0x2e, 0x2e, 0x8f, 0xd4, 0x9c,
+ 0x9c, 0xfc, 0xf0, 0xfc, 0xa2, 0x9c, 0x14, 0x21, 0x41, 0x3d, 0x98, 0x93, 0xf4, 0xa0, 0xee, 0x91,
+ 0x12, 0x42, 0x16, 0x82, 0xd8, 0xad, 0xc4, 0x90, 0xc4, 0x06, 0x16, 0x34, 0x06, 0x04, 0x00, 0x00,
+ 0xff, 0xff, 0x72, 0xb6, 0x62, 0x67, 0xcd, 0x00, 0x00, 0x00,
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConn
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion4
+
+// ApiServerClient is the client API for ApiServer service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type ApiServerClient interface {
+ // 接口
+ HelloWorld(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
+}
+
+type apiServerClient struct {
+ cc *grpc.ClientConn
+}
+
+func NewApiServerClient(cc *grpc.ClientConn) ApiServerClient {
+ return &apiServerClient{cc}
+}
+
+func (c *apiServerClient) HelloWorld(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) {
+ out := new(Response)
+ err := c.cc.Invoke(ctx, "/protobuf.ApiServer/HelloWorld", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// ApiServerServer is the server API for ApiServer service.
+type ApiServerServer interface {
+ // 接口
+ HelloWorld(context.Context, *Request) (*Response, error)
+}
+
+// UnimplementedApiServerServer can be embedded to have forward compatible implementations.
+type UnimplementedApiServerServer struct {
+}
+
+func (*UnimplementedApiServerServer) HelloWorld(ctx context.Context, req *Request) (*Response, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method HelloWorld not implemented")
+}
+
+func RegisterApiServerServer(s *grpc.Server, srv ApiServerServer) {
+ s.RegisterService(&_ApiServer_serviceDesc, srv)
+}
+
+func _ApiServer_HelloWorld_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(Request)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(ApiServerServer).HelloWorld(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/protobuf.ApiServer/HelloWorld",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(ApiServerServer).HelloWorld(ctx, req.(*Request))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+var _ApiServer_serviceDesc = grpc.ServiceDesc{
+ ServiceName: "protobuf.ApiServer",
+ HandlerType: (*ApiServerServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "HelloWorld",
+ Handler: _ApiServer_HelloWorld_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "pb.proto",
+}
diff --git a/proto/pb.proto b/proto/pb.proto
new file mode 100644
index 0000000..75198d6
--- /dev/null
+++ b/proto/pb.proto
@@ -0,0 +1,26 @@
+syntax = "proto3";
+
+package protobuf;
+
+// ApiServer api 接口
+service ApiServer {
+ // HelloWorld 接口
+ rpc HelloWorld (Request) returns (Response) {
+ }
+}
+
+// 请求
+message Request {
+ // UserName 用户昵称
+ string userName = 1;
+}
+
+// 响应
+message Response {
+ // 状态码
+ int32 code = 1;
+ // 状态码说明
+ string msg = 2;
+ // Data 返回数据
+ string data = 3;
+}
\ No newline at end of file
diff --git a/server/client/grpc_client.go b/server/client/grpc_client.go
new file mode 100644
index 0000000..475d337
--- /dev/null
+++ b/server/client/grpc_client.go
@@ -0,0 +1,66 @@
+/**
+* Created by GoLand.
+* User: link1st
+* Date: 2019-08-15
+* Time: 21:03
+ */
+
+package client
+
+import (
+ "context"
+ "fmt"
+ "google.golang.org/grpc"
+ "strings"
+ "time"
+)
+
+type GrpcSocket struct {
+ conn *grpc.ClientConn
+ address string
+}
+
+func NewGrpcSocket(address string) (s *GrpcSocket) {
+ var (
+ newAddr string
+ )
+ arr := strings.Split(address, "//")
+ if len(arr) >= 2 {
+ newAddr = arr[1]
+ }
+ s = &GrpcSocket{
+ address: newAddr,
+ }
+ return
+}
+
+func (g *GrpcSocket) getAddress() (address string) {
+ return g.address
+}
+
+// 关闭
+func (g *GrpcSocket) Close() (err error) {
+ if g == nil {
+ return
+ }
+ if g.conn == nil {
+ return
+ }
+ g.conn.Close()
+ return
+}
+
+// Link 建立连接
+func (g *GrpcSocket) Link() (err error) {
+ ctx, _ := context.WithTimeout(context.Background(), 3*time.Second)
+ conn, err := grpc.DialContext(ctx, g.address, grpc.WithInsecure(), grpc.WithBlock())
+ if err != nil {
+ return fmt.Errorf("GetConn: 连接失败 address:%s %w", g.address, err)
+ }
+ g.conn = conn
+ return
+}
+
+func (g *GrpcSocket) GetConn() (conn *grpc.ClientConn) {
+ return g.conn
+}
diff --git a/server/dispose.go b/server/dispose.go
index ee28403..3d078a3 100644
--- a/server/dispose.go
+++ b/server/dispose.go
@@ -90,6 +90,15 @@ func Dispose(concurrency, totalNumber uint64, request *model.Request) {
panic(data)
}
+ case model.FormTypeGRPC:
+ // 连接以后再启动协程
+ ws := client.NewGrpcSocket(request.Url)
+ err := ws.Link()
+ if err != nil {
+ fmt.Println("连接失败:", i, err)
+ continue
+ }
+ go golink.Grpc(i, ch, totalNumber, &wg, request, ws)
default:
// 类型不支持
wg.Done()
diff --git a/server/golink/grpc_link.go b/server/golink/grpc_link.go
new file mode 100644
index 0000000..a0de908
--- /dev/null
+++ b/server/golink/grpc_link.go
@@ -0,0 +1,79 @@
+/**
+* Created by GoLand.
+* User: link1st
+* Date: 2019-08-21
+* Time: 15:43
+ */
+
+package golink
+
+import (
+ "context"
+ pb "go-stress-testing/proto"
+ "sync"
+ "time"
+
+ "go-stress-testing/heper"
+ "go-stress-testing/model"
+ "go-stress-testing/server/client"
+)
+
+// Grpc grpc 接口请求
+func Grpc(chanId uint64, ch chan<- *model.RequestResults, totalNumber uint64, wg *sync.WaitGroup, request *model.Request, ws *client.GrpcSocket) {
+
+ defer func() {
+ wg.Done()
+ }()
+ defer func() {
+ ws.Close()
+ }()
+ for i := uint64(0); i < totalNumber; i++ {
+ grpcRequest(chanId, ch, i, request, ws)
+ }
+ return
+}
+
+// 请求
+func grpcRequest(chanId uint64, ch chan<- *model.RequestResults, i uint64, request *model.Request, ws *client.GrpcSocket) {
+ var (
+ startTime = time.Now()
+ isSucceed = false
+ errCode = model.HttpOk
+ )
+
+ // 需要发送的数据
+ conn := ws.GetConn()
+ if conn == nil {
+ errCode = model.RequestErr
+ } else {
+ // TODO::请求接口示例
+ c := pb.NewApiServerClient(conn)
+ var (
+ ctx = context.Background()
+ req = &pb.Request{
+ UserName: request.Body,
+ }
+ )
+ rsp, err := c.HelloWorld(ctx, req)
+ // fmt.Printf("rsp:%+v", rsp)
+ if err != nil {
+ errCode = model.RequestErr
+ } else {
+ // 200 为成功
+ if rsp.Code != 200 {
+ errCode = model.RequestErr
+ } else {
+ isSucceed = true
+ }
+ }
+ }
+ requestTime := uint64(heper.DiffNano(startTime))
+ requestResults := &model.RequestResults{
+ Time: requestTime,
+ IsSucceed: isSucceed,
+ ErrCode: errCode,
+ }
+ requestResults.SetId(chanId, i)
+
+ ch <- requestResults
+}
diff --git a/tests/grpc/main.go b/tests/grpc/main.go
new file mode 100644
index 0000000..c144fb9
--- /dev/null
+++ b/tests/grpc/main.go
@@ -0,0 +1,51 @@
+/**
+* Created by GoLand.
+* User: link1st
+* Date: 2021/2/3
+* Time: 23:44
+ */
+
+package main
+
+import (
+ "context"
+ "fmt"
+ pb "go-stress-testing/proto"
+ "google.golang.org/grpc"
+ "log"
+ "net"
+)
+
+const (
+ // port 监听端口
+ port = ":8099"
+)
+
+// server is used to implement helloWorld.GreeterServer.
+type server struct {
+ pb.UnimplementedApiServerServer
+}
+
+// HelloWorld hello world 接口
+func (s *server) HelloWorld(_ context.Context, req *pb.Request) (rsp *pb.Response, err error) {
+ rsp = &pb.Response{
+ Code: 200,
+ Msg: "success",
+ Data: fmt.Sprintf("hello %s !", req.UserName),
+ }
+ return
+}
+
+// main 主函数
+func main() {
+ fmt.Println("trpc server 启动中...")
+ lis, err := net.Listen("tcp", port)
+ if err != nil {
+ log.Fatalf("failed to listen: %v", err)
+ }
+ s := grpc.NewServer()
+ pb.RegisterApiServerServer(s, &server{})
+ if err := s.Serve(lis); err != nil {
+ log.Fatalf("failed to serve: %v", err)
+ }
+}
From 17ab17392d318a347c4067b56d5d5ccc9adfd920 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Thu, 4 Feb 2021 01:01:16 +0800
Subject: [PATCH 67/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3=20--?=
=?UTF-8?q?=20grpc=20=E6=8E=A5=E5=8F=A3=E5=8E=8B=E6=B5=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/README.md b/README.md
index d4125f8..8c8932e 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,8 @@
- 单台机器对 HTTP 短连接 QPS 1W+ 的压测实战
- 单台机器 100W 长连接的压测实战
+- 对 grpc 接口进行压测
+> 用户可以手动扩展支持 私有协议压测
## 目录
- [1、项目说明](#1项目说明)
@@ -31,6 +33,7 @@
- [4.2 用法](#42-用法)
- [4.3 实现](#43-实现)
- [4.4 go-stress-testing 对 Golang web 压测](#44-go-stress-testing-对-golang-web-压测)
+ - [4.5 grpc压测](#45-grpc压测)
- [5、压测工具的比较](#5压测工具的比较)
- [5.1 比较](#51-比较)
- [5.2 如何选择压测工具](#52-如何选择压测工具)
@@ -625,6 +628,28 @@ func main() {
从压测的结果上看:效果还不错,压测QPS有接近2W
+### 4.5 grpc压测
+- 介绍如何压测 grpc 接口
+> [添加对 grpc 接口压测 commit](https://github.com/link1st/go-stress-testing/commit/2b4b14aaf026d08276531cf76f42de90efd3bc61)
+- 1. 启动Server
+```shell script
+# 进入 grpc server 目录
+cd tests/grpc
+
+# 启动 grpc server
+go run main.go
+```
+
+- 2. 对 grpc server 协议进行压测
+```shell script
+# 回到项目根目录
+go run main.go -c 300 -n 1000 -u grpc://127.0.0.1:8099 -data world
+```
+
+- 如何扩展其它私有协议
+> 由于私有协议、grpc 协议 都涉及到代码的书写,所以需要 编写go 的代码才能完成
+> 参考 [添加对 grpc 接口压测 commit](https://github.com/link1st/go-stress-testing/commit/2b4b14aaf026d08276531cf76f42de90efd3bc61)
+
## 5、压测工具的比较
### 5.1 比较
From 752ea8aa476dade1d2d934aac6e4311f2bbea5ef Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Thu, 4 Feb 2021 01:05:01 +0800
Subject: [PATCH 68/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 8c8932e..12eda73 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
- 单台机器对 HTTP 短连接 QPS 1W+ 的压测实战
- 单台机器 100W 长连接的压测实战
- 对 grpc 接口进行压测
-> 用户可以手动扩展支持 私有协议压测
+> 简单扩展即可支持 私有协议
## 目录
- [1、项目说明](#1项目说明)
From 5e2646cc6e2429072b43cd75e84d71decef2d522 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Thu, 4 Feb 2021 01:10:31 +0800
Subject: [PATCH 69/75] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 12eda73..fc302b3 100644
--- a/README.md
+++ b/README.md
@@ -641,9 +641,29 @@ go run main.go
```
- 2. 对 grpc server 协议进行压测
-```shell script
+```
# 回到项目根目录
go run main.go -c 300 -n 1000 -u grpc://127.0.0.1:8099 -data world
+
+开始启动 并发数:300 请求数:1000 请求参数:
+request:
+ form:grpc
+ url:grpc://127.0.0.1:8099
+ method:POST
+ headers:map[Content-Type:application/x-www-form-urlencoded; charset=utf-8]
+ data:world
+ verify:
+ timeout:30s
+ debug:false
+
+─────┬───────┬───────┬───────┬────────┬────────┬────────┬────────┬────────┬────────┬────────
+ 耗时 │ 并发数 │ 成功数 │ 失败数 │ qps │最长耗时 │最短耗时 │平均耗时 │下载字节 │字节每秒 │ 错误码
+─────┼───────┼───────┼───────┼────────┼────────┼────────┼────────┼────────┼────────┼────────
+ 1s│ 186│ 14086│ 0│34177.69│ 22.40│ 0.63│ 8.78│ │ │200:14086
+ 2s│ 265│ 30408│ 0│26005.09│ 32.68│ 0.63│ 11.54│ │ │200:30408
+ 3s│ 300│ 46747│ 0│21890.46│ 40.84│ 0.63│ 13.70│ │ │200:46747
+ 4s│ 300│ 62837│ 0│20057.06│ 45.81│ 0.63│ 14.96│ │ │200:62837
+ 5s│ 300│ 79119│ 0│19134.52│ 45.81│ 0.63│ 15.68│ │ │200:79119
```
- 如何扩展其它私有协议
From 824a493937d2c08a6a420ddd82e9ed39c1eb3c9e Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Thu, 4 Feb 2021 01:12:01 +0800
Subject: [PATCH 70/75] =?UTF-8?q?flag=20=E6=9C=80=E4=BD=B3=E5=AE=9E?=
=?UTF-8?q?=E8=B7=B5=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
main.go | 46 ++++++++++++++++++++++------------------------
1 file changed, 22 insertions(+), 24 deletions(-)
diff --git a/main.go b/main.go
index 3e14d83..b7e4861 100644
--- a/main.go
+++ b/main.go
@@ -28,46 +28,44 @@ func (a *array) Set(s string) error {
return nil
}
-// go 实现的压测工具
-//
-// 编译可执行文件
-//go:generate go build main.go
-func main() {
-
- runtime.GOMAXPROCS(1)
-
- var (
- concurrency uint64 // 并发数
- totalNumber uint64 // 请求数(单个并发/协程)
- debugStr string // 是否是debug
- requestUrl string // 压测的url 目前支持,http/https ws/wss
- path string // curl文件路径 http接口压测,自定义参数设置
- verify string // verify 验证方法 在server/verify中 http 支持:statusCode、json webSocket支持:json
- headers array // 自定义头信息传递给服务器
- body string // HTTP POST方式传送数据
- )
+var (
+ concurrency uint64 = 1 // 并发数
+ totalNumber uint64 = 1 // 请求数(单个并发/协程)
+ debugStr = "false" // 是否是debug
+ requestUrl string // 压测的url 目前支持,http/https ws/wss
+ path string // curl文件路径 http接口压测,自定义参数设置
+ verify string // verify 验证方法 在server/verify中 http 支持:statusCode、json webSocket支持:json
+ headers array // 自定义头信息传递给服务器
+ body string // HTTP POST方式传送数据
+)
- flag.Uint64Var(&concurrency, "c", 1, "并发数")
- flag.Uint64Var(&totalNumber, "n", 1, "请求数(单个并发/协程)")
- flag.StringVar(&debugStr, "d", "false", "调试模式")
+func init() {
+ flag.Uint64Var(&concurrency, "c", concurrency, "并发数")
+ flag.Uint64Var(&totalNumber, "n", totalNumber, "请求数(单个并发/协程)")
+ flag.StringVar(&debugStr, "d", debugStr, "调试模式")
flag.StringVar(&requestUrl, "u", "", "压测地址")
flag.StringVar(&path, "p", "", "curl文件路径")
flag.StringVar(&verify, "v", "", "验证方法 http 支持:statusCode、json webSocket支持:json")
flag.Var(&headers, "H", "自定义头信息传递给服务器 示例:-H 'Content-Type: application/json'")
flag.StringVar(&body, "data", "", "HTTP POST方式传送数据")
-
// 解析参数
flag.Parse()
+}
+
+// go 实现的压测工具
+// 编译可执行文件
+//go:generate go build main.go
+func main() {
+
+ runtime.GOMAXPROCS(1)
if concurrency == 0 || totalNumber == 0 || (requestUrl == "" && path == "") {
fmt.Printf("示例: go run main.go -c 1 -n 1 -u https://www.baidu.com/ \n")
fmt.Printf("压测地址或curl路径必填 \n")
fmt.Printf("当前请求参数: -c %d -n %d -d %v -u %s \n", concurrency, totalNumber, debugStr, requestUrl)
-
flag.Usage()
return
}
-
debug := strings.ToLower(debugStr) == "true"
request, err := model.NewRequest(requestUrl, verify, 0, debug, path, headers, body)
if err != nil {
From 4b4ad0a812981fdda75ded8d22a6b1a175b11451 Mon Sep 17 00:00:00 2001
From: Link <562117637@qq.com>
Date: Wed, 10 Mar 2021 20:23:39 +0800
Subject: [PATCH 71/75] Update http_client.go
add `req.Close`
---
server/client/http_client.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/server/client/http_client.go b/server/client/http_client.go
index 75445fd..af6e27a 100644
--- a/server/client/http_client.go
+++ b/server/client/http_client.go
@@ -42,6 +42,7 @@ func HttpRequest(method, url string, body io.Reader, headers map[string]string,
return
}
+ req.Close = true
// 在req中设置Host,解决在header中设置Host不生效问题
if _, ok := headers["Host"]; ok {
req.Host = headers["Host"]
From e4d4845b5268b93057528b08dcd146bd2c801011 Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Thu, 1 Apr 2021 12:40:40 +0800
Subject: [PATCH 72/75] add curl http put
---
helper/helper.go | 30 ++++++++++++++++++++++++++++++
heper/heper.go | 18 ------------------
model/curl_model.go | 23 +++++++++++------------
server/client/http_client.go | 6 ++++--
server/golink/grpc_link.go | 14 +++++++++-----
server/golink/websocket_link.go | 5 +++--
6 files changed, 57 insertions(+), 39 deletions(-)
create mode 100644 helper/helper.go
delete mode 100644 heper/heper.go
diff --git a/helper/helper.go b/helper/helper.go
new file mode 100644
index 0000000..489e0e7
--- /dev/null
+++ b/helper/helper.go
@@ -0,0 +1,30 @@
+/**
+* Created by GoLand.
+* User: link1st
+* Date: 2019-08-21
+* Time: 15:40
+ */
+
+package helper
+
+import (
+ "time"
+)
+
+// DiffNano 时间差,纳秒
+func DiffNano(startTime time.Time) (diff int64) {
+ diff = int64(time.Since(startTime))
+ return
+}
+
+// InArrayStr 判断字符串是否在数组内
+func InArrayStr(str string, arr []string) (inArray bool) {
+ for _, s := range arr {
+ if s == str {
+ inArray = true
+ break
+ }
+ }
+ return
+}
+
diff --git a/heper/heper.go b/heper/heper.go
deleted file mode 100644
index 19d30dd..0000000
--- a/heper/heper.go
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
-* Created by GoLand.
-* User: link1st
-* Date: 2019-08-21
-* Time: 15:40
- */
-
-package heper
-
-import (
- "time"
-)
-
-// 时间差,纳秒
-func DiffNano(startTime time.Time) (diff int64) {
- diff = int64(time.Since(startTime))
- return
-}
diff --git a/model/curl_model.go b/model/curl_model.go
index 320aaff..e51fec8 100644
--- a/model/curl_model.go
+++ b/model/curl_model.go
@@ -13,6 +13,8 @@ import (
"io/ioutil"
"os"
"strings"
+
+ "go-stress-testing/helper"
)
// curl参数解析
@@ -181,24 +183,20 @@ func (c *CURL) GetUrl() (url string) {
// GetMethod
func (c *CURL) GetMethod() (method string) {
- method = "GET"
-
- body := c.GetBody()
-
- if len(body) > 0 {
- return "POST"
- }
-
keys := []string{"-X", "--request"}
value := c.getDataValue(keys)
-
if len(value) <= 0 {
-
return
}
-
method = strings.ToUpper(value[0])
-
+ if helper.InArrayStr(method, []string{"GET", "POST", "PUT", "DELETE"}) {
+ return method
+ }
+ method = "GET"
+ body := c.GetBody()
+ if len(body) > 0 {
+ return "POST"
+ }
return
}
@@ -255,3 +253,4 @@ func (c *CURL) getPostForm() (body string) {
return
}
+
diff --git a/server/client/http_client.go b/server/client/http_client.go
index af6e27a..b0fe7bc 100644
--- a/server/client/http_client.go
+++ b/server/client/http_client.go
@@ -9,12 +9,13 @@ package client
import (
"crypto/tls"
- "go-stress-testing/heper"
"io"
"log"
"net/http"
"os"
"time"
+
+ "go-stress-testing/helper"
)
var logErr = log.New(os.Stderr, "", 0)
@@ -61,7 +62,7 @@ func HttpRequest(method, url string, body io.Reader, headers map[string]string,
startTime := time.Now()
resp, err = client.Do(req)
- requestTime = uint64(heper.DiffNano(startTime))
+ requestTime = uint64(helper.DiffNano(startTime))
if err != nil {
logErr.Println("请求失败:", err)
@@ -73,3 +74,4 @@ func HttpRequest(method, url string, body io.Reader, headers map[string]string,
return
}
+
diff --git a/server/golink/grpc_link.go b/server/golink/grpc_link.go
index a0de908..cd43c02 100644
--- a/server/golink/grpc_link.go
+++ b/server/golink/grpc_link.go
@@ -9,17 +9,19 @@ package golink
import (
"context"
- pb "go-stress-testing/proto"
"sync"
"time"
- "go-stress-testing/heper"
+ "go-stress-testing/helper"
+ pb "go-stress-testing/proto"
+
"go-stress-testing/model"
"go-stress-testing/server/client"
)
// Grpc grpc 接口请求
-func Grpc(chanId uint64, ch chan<- *model.RequestResults, totalNumber uint64, wg *sync.WaitGroup, request *model.Request, ws *client.GrpcSocket) {
+func Grpc(chanId uint64, ch chan<- *model.RequestResults, totalNumber uint64, wg *sync.WaitGroup,
+ request *model.Request, ws *client.GrpcSocket) {
defer func() {
wg.Done()
@@ -34,7 +36,8 @@ func Grpc(chanId uint64, ch chan<- *model.RequestResults, totalNumber uint64, wg
}
// 请求
-func grpcRequest(chanId uint64, ch chan<- *model.RequestResults, i uint64, request *model.Request, ws *client.GrpcSocket) {
+func grpcRequest(chanId uint64, ch chan<- *model.RequestResults, i uint64, request *model.Request,
+ ws *client.GrpcSocket) {
var (
startTime = time.Now()
isSucceed = false
@@ -67,7 +70,7 @@ func grpcRequest(chanId uint64, ch chan<- *model.RequestResults, i uint64, reque
}
}
}
- requestTime := uint64(heper.DiffNano(startTime))
+ requestTime := uint64(helper.DiffNano(startTime))
requestResults := &model.RequestResults{
Time: requestTime,
IsSucceed: isSucceed,
@@ -77,3 +80,4 @@ func grpcRequest(chanId uint64, ch chan<- *model.RequestResults, i uint64, reque
ch <- requestResults
}
+
diff --git a/server/golink/websocket_link.go b/server/golink/websocket_link.go
index 5b58c7c..caffdad 100644
--- a/server/golink/websocket_link.go
+++ b/server/golink/websocket_link.go
@@ -12,7 +12,7 @@ import (
"sync"
"time"
- "go-stress-testing/heper"
+ "go-stress-testing/helper"
"go-stress-testing/model"
"go-stress-testing/server/client"
)
@@ -105,7 +105,7 @@ func webSocketRequest(chanId uint64, ch chan<- *model.RequestResults, i uint64,
}
}
- requestTime := uint64(heper.DiffNano(startTime))
+ requestTime := uint64(helper.DiffNano(startTime))
requestResults := &model.RequestResults{
Time: requestTime,
@@ -118,3 +118,4 @@ func webSocketRequest(chanId uint64, ch chan<- *model.RequestResults, i uint64,
ch <- requestResults
}
+
From 537c368ab0f5d62741898b24cc5c5252d926b7bb Mon Sep 17 00:00:00 2001
From: link1st <562117637@qq.com>
Date: Thu, 1 Apr 2021 12:52:50 +0800
Subject: [PATCH 73/75] add default method
---
model/curl_model.go | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/model/curl_model.go b/model/curl_model.go
index e51fec8..db4a5cd 100644
--- a/model/curl_model.go
+++ b/model/curl_model.go
@@ -186,12 +186,17 @@ func (c *CURL) GetMethod() (method string) {
keys := []string{"-X", "--request"}
value := c.getDataValue(keys)
if len(value) <= 0 {
- return
+ return c.defaultMethod()
}
method = strings.ToUpper(value[0])
if helper.InArrayStr(method, []string{"GET", "POST", "PUT", "DELETE"}) {
return method
}
+ return c.defaultMethod()
+}
+
+// defaultMethod 获取默认方法
+func (c *CURL) defaultMethod() (method string) {
method = "GET"
body := c.GetBody()
if len(body) > 0 {
@@ -254,3 +259,4 @@ func (c *CURL) getPostForm() (body string) {
return
}
+
From dd61ddd77626c97f56416b563d963601b28f76c5 Mon Sep 17 00:00:00 2001
From: wang
Date: Thu, 1 Apr 2021 17:45:11 +0800
Subject: [PATCH 74/75] =?UTF-8?q?=E7=94=9F=E6=88=90=E9=9A=8F=E6=9C=BA?=
=?UTF-8?q?=E5=8F=82=E6=95=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
生成随机参数 比如 go run main.go -c 10 -n 10000 -u http://192.168.0.50:8091/data -data "flag=AccessRecord&name=random12&pic=random2&about=about3"
---
helper/helper.go | 10 ++++++++++
model/request_model.go | 15 +++++++++++++--
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/helper/helper.go b/helper/helper.go
index 489e0e7..f886f69 100644
--- a/helper/helper.go
+++ b/helper/helper.go
@@ -8,6 +8,7 @@
package helper
import (
+ "math/rand"
"time"
)
@@ -28,3 +29,12 @@ func InArrayStr(str string, arr []string) (inArray bool) {
return
}
+func GetRandomString(len int) string {
+ r := rand.New(rand.NewSource(time.Now().Unix()))
+ bytes := make([]byte, len)
+ for i := 0; i < len; i++ {
+ b := r.Intn(26) + 65
+ bytes[i] = byte(b)
+ }
+ return string(bytes)
+}
diff --git a/model/request_model.go b/model/request_model.go
index 02aa87a..066f411 100644
--- a/model/request_model.go
+++ b/model/request_model.go
@@ -15,6 +15,9 @@ import (
"strings"
"sync"
"time"
+ "regexp"
+ "strconv"
+ "go-stress-testing/helper"
)
const (
@@ -81,8 +84,16 @@ type Request struct {
}
func (r *Request) GetBody() (body io.Reader) {
- body = strings.NewReader(r.Body)
-
+ reg1 := regexp.MustCompile(`random(\d+)?`)
+ result := r.Body
+ match := reg1.FindAllStringSubmatch(result, -1)
+ if match != nil {
+ for _, v := range match {
+ l, _ := strconv.Atoi(v[1])
+ result = strings.Replace(result, v[0], helper.GetRandomString(l), 1)
+ }
+ }
+ body = strings.NewReader(result)
return
}
From 47142375f71e572af61aaacd92d35095da4c757d Mon Sep 17 00:00:00 2001
From: wang
Date: Fri, 2 Apr 2021 17:46:52 +0800
Subject: [PATCH 75/75] =?UTF-8?q?=E6=97=B6=E9=97=B4=E7=A7=8D=E5=AD=90?=
=?UTF-8?q?=E6=94=B9=E4=B8=80=E4=B8=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
helper/helper.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/helper/helper.go b/helper/helper.go
index f886f69..666331a 100644
--- a/helper/helper.go
+++ b/helper/helper.go
@@ -30,7 +30,7 @@ func InArrayStr(str string, arr []string) (inArray bool) {
}
func GetRandomString(len int) string {
- r := rand.New(rand.NewSource(time.Now().Unix()))
+ r := rand.New(rand.NewSource(time.Now().UnixNano()))
bytes := make([]byte, len)
for i := 0; i < len; i++ {
b := r.Intn(26) + 65