共计 9432 个字符,预计需要花费 24 分钟才能阅读完成。
要求同一 0.1s 内把 1 个 post 的 curl 命令多并发 5 次 /10 次同一时间发出请求 脚本要求 bash test.sh 请输入并发次数: 例如 5 次就输入 5 输入需要同时并发执行的 curl 命令: (以下命令只做举例非实际要执行的命令,要求可自定义。) 然后回车即可 要求同一时刻发出 5 次上述 curl 请求。 网上找的方法好多都不是同一时刻发出这个 post,每个请求有 0.5- 1 秒左右的时差无法满足要求。 |
网友回复:
注册 : 使用 ’&’+wait 实现“多线程”
a8866051: 直接 xargs –P 5 curl xxxx 不行吗?
mjj666zzz: 这是撸腾讯啥接口?
liugogal: 白 ** 大厂?
阿里云 : 不是,只是随便拿一个举例子
大吊 : bash + curl 就只能多进程吧..
a8866051: curl –parallel –parallel-immediate –parallel-max 10
teardrops: 私聊我报价吧,用 python 给你写
zxxx: 是多进程但是没法同时并发,这个只是执行完一个马上扔后台然后执行下一个
注册 : 用管道呢,要不就换个性能高的机器
注册 : python 不是伪多线程嘛
mjj666zzz: 这种就用其它语言实现嘛,脚本语言不适合干这些,你延时需要 0.1s,那就用 cpp,先开几个线程等着,线程每 10ms 检查一次,有请求就立马发送不就完了,这样才能真正的保证延时
heibaihuali: 就是 cc 攻击嘛,github 上很多的
heibaihuali: for (int i=0;i<10;i++) pthread_create(xxxx)
好鸭 : python 可以 gil 锁并不影响并发
sdqu: python 异步 gather 应该是同时执行的
Mr.lin: 不是拿来攻击,我需要也就 5 -20 并发执行一次,不是几百
honus: 大佬直接报个价吧,因为收益极小特多大的价钱我应该给不了
a8866051: 性能高的用这方法也没法 5 -10 次执行在 0.1s 内发起全部执行命令,至少 2,3 秒
注册 : 好像这样就行了,你可以试一下,最后的 & 要保留 read -p “ 输入并发数: ” num for i in {1..$num};do curl https://www.baidu.com & done 复制代码
注册 : 执行直接没反应。。。
好鸭 : 追求性能的话可以 golang,不着急的话明天,一个甲骨文?
a8866051: 测试请求无法同一时刻发出
251768938: 要求 10ms 以内同时发出么?
a8866051: https://github.com/jneeee/qos_tool 我写过一个 python qos 脚本,并发可以很大。拿去改一改不是很难
zxxx: 越短越好,最好同一时刻
jaymi: 主要是自己太菜了
a8866051: PHP 是最好的语言。workerman 版本:https://www.workerman.net/doc/workerman/components/workerman-http-client.html swoole 版本:0. https://wiki.swoole.com/#/coroutine/multi_call 1. https://wiki.swoole.com/#/coroutine/wait_group
a8866051: cli 应用,配和 swoole-cli 写一些 shell 脚本,贼爽贼方便
注册 : bash 肯定不稳定,一个是每个进程启动时间就在 20 毫秒左右浮动了。然后还有 tcp,tls 过程。送你一个我自己的羊毛脚本。会针对每个链接先发起一个请求做预热 keepalive 或者 http2 链接,然后复用之前的链接来减少握手阶段造成的误差,20 并发测试百度在 20 毫秒以内。把 POST 改成自己需要的就行了 package main import (“fmt” “io” “io/ioutil” “log” “net” “net/http” “net/url” “strings” “sync” “time”) const co = 20 func main() { wg := sync.WaitGroup{} wg2 := sync.WaitGroup{} client := &http.Client{ Transport: &http.Transport{ DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second,}).DialContext, ForceAttemptHTTP2: true, MaxIdleConns: 100, MaxIdleConnsPerHost: 100, IdleConnTimeout: 60 * time.Second, }, Timeout: 20 * time.Second, } wg.Add(co) wg2.Add(co) for i := 0; i < co; i++ {go func(t int) {defer wg2.Done() // 建立链接,Keepalive r, err := client.Get(“http://www.baidu.com/recharge.php”) _, err = io.Copy(ioutil.Discard, r.Body) if err != nil {log.Fatalln(err) } if t == 0 {fmt.Println(“ 预热完成, 即将执行 ”) time.Sleep(time.Second * 5) } // 线程同步 wg.Done() wg.Wait() // 同步发起请求 formData := url.Values{“username”: {“x”}, “key”: {“xxx”}, } req, err := http.NewRequest(“POST”, “http://www.baidu.com/recharge.php”, strings.NewReader(formData.Encode())) if err != nil {log.Fatalln(err) } req.Header.Set(“x-requested-with”, “XMLHttpRequest”) req.Header.Set(“Content-Type”, “application/x-www-form-urlencoded”) req.Header.Set(“cookie”, “account=528250;”) resp, err := client.Do(req) if err != nil {log.Fatalln(err) } fmt.Println(“ 完成时间 ”, time.Now().String()) defer func() { _ = resp.Body.Close() }() body, err := ioutil.ReadAll(resp.Body) if err != nil {log.Fatalln(err) } fmt.Println(string(body)) }(i) } wg2.Wait()}
注册 : c 语言 原生 tcp 小程序 可以吧
host0108: 晚上睡不着,用 Go 瞎鸡儿写的一个并发 curl 工具(curl-pnrt)能应付楼主的需求 和原版有点区别 (工具在附件上 编译环境是 centos 7 amd64 版本,mac 是 m1 就没贴了) 附件:https://wwi.lanzoup.com/iYhds09cnokj 使用步骤:可以直接浏览器 [Copy as cURL] 进行改造一下就好了 比如:curl ‘https://static.leetcode.cn/cn-mono-assets/production/main/runtime~main.8725179e.js’ -H ‘sec-ch-ua: “.Not/A)Brand”;v=”99″, “Google Chrome”;v=”103″, “Chromium”;v=”103″‘ -H ‘Referer: https://leetcode.cn/’ -H ‘DNT: 1’ -H ‘sec-ch-ua-mobile: ?0’ -H ‘User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36’ -H ‘sec-ch-ua-platform: “macOS”‘ –compressed 复制代码 需要把 –compressed 去掉,url 的地址部分 前缀需要加个 -t(懒得写位置顺序)-c 后面紧跟的是并发量 ./curl-pnrt -c 900 -t ‘https://static.leetcode.cn/cn-mono-assets/production/main/runtime~main.8725179e.js’ -H ‘sec-ch-ua: “.Not/A)Brand”;v=”99″, “Google Chrome”;v=”103″, “Chromium”;v=”103″‘ -H ‘Referer: https://leetcode.cn/’ -H ‘DNT: 1’ -H ‘sec-ch-ua-mobile: ?0’ -H ‘User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36’ -H ‘sec-ch-ua-platform: “macOS”‘ 复制代码 其他的几乎一样 (除非就没写那个功能,哈哈~) -c: 就是想要的并发数 1000 0.3s 左右(可能是同一个地域的服务器,所以快些)-t: 目标 url -X: 默认 get , 比如:-X POST 就是 post -H: 和原版 crul 一样 -d: get 的格式和原版一样 key1=xxx,post 的话和原版一样,不过记得加个 -H ‘Content-Type: xxxx/xxx’ 的类型 -p: 打印响应的信息 效果如下:源码:package main import (“bytes” “flag” “fmt” “io” “io/ioutil” “net/http” “net/url” “strings” “sync” “time”) type httpClient struct {client *http.Client} type stringsValue []string func newStringsValue(val string, p *[]string) *stringsValue {if val != “” { *p = append(*p, val) } return (*stringsValue)(p) } func (s *stringsValue) Set(val string) error {*s = append(*s, val) return nil } func (s *stringsValue) Get() interface{} {return []string(*s) } func (s *stringsValue) String() string { return fmt.Sprintln([]string(*s)) } func main() { ht := &httpClient{} ht.client = &http.Client{Transport: &http.Transport{ MaxIdleConns: 900, MaxIdleConnsPerHost: 900, IdleConnTimeout: time.Second * 30,}, } now := time.Now() httpUrl := “” headers := &[]string{} flag.StringVar(&httpUrl, “t”, “”, “Please enter the correct URL: http/https”) count := flag.Int(“c”, 1, “Number of concurrent runs: Default is 1”) flag.Var(newStringsValue(“”, headers), “H”, “Example Imitate the curl command -h”) protocol := flag.String(“X”, “GET”, “-X POST|GET”) data := flag.String(“d”, “”, “support JSON”) var isPrintResp bool flag.BoolVar(&isPrintResp, “p”, false, “Whether to output RESP”) //userAgent := flag.String(“A”, “”, “User-Agent”) flag.Parse() if httpUrl == “” { fmt.Println(“Please enter the correct URL”) } headerMap := map[string]string{} for _, s := range *headers { split := strings.Split(s, “: “) if len(split) == 2 {headerMap[split[0]] = split[1] } else {fmt.Println(“header fail”) return } } //fmt.Println(*headers) waitGroup := sync.WaitGroup{} *protocol = strings.ToUpper(*protocol) //time.Sleep(3 * time.Second) for i := 0; i < *count; i++ {fmt.Printf(“”) go func() { waitGroup.Add(1) if *protocol == “GET” {values := url.Values{} if data != nil && *data != “*” {for _, s := range strings.Split(*data, “&”) {split := strings.Split(s, “=”) if len(split) == 2 {values.Set(split[0], split[1]) } } } if resp, err := ht.GET(httpUrl, values); err != nil {if err == io.EOF { if isPrintResp { fmt.Println(string(resp)) } } fmt.Println(err) } else {if isPrintResp { fmt.Println(string(resp)) } } } else if *protocol == “POST” {if resp, err := ht.POST(httpUrl, []byte(*data), headerMap); err != nil {if err == io.EOF { if isPrintResp { fmt.Println(string(resp)) } } fmt.Println(err) } else {if isPrintResp { fmt.Println(string(resp)) } } } waitGroup.Done()}()} waitGroup.Wait() fmt.Println() fmt.Printf(“time spent: %v s”, time.Since(now).Seconds()) fmt.Println()} func (ht *httpClient) GET(httpUrl string, queryStr url.Values) (res []byte, err error) {var Url *url.URL Url, err = url.Parse(httpUrl) if err != nil {fmt.Printf(“parse fail:%v”, err) return nil, err } Url.RawQuery = queryStr.Encode() resp, err := ht.client.Get(Url.String()) if err != nil {fmt.Println(“err:”, err) return nil, err } defer resp.Body.Close() return ioutil.ReadAll(resp.Body) } func (ht *httpClient) POST(httpUrl string, jsonByte []byte, headerMap map[string]string) (res []byte, err error) {var Url *url.URL Url, err = url.Parse(httpUrl) if err != nil {fmt.Printf(“parse fail:%v”, err) return nil, err } request, err := http.NewRequest(“POST”, Url.String(), bytes.NewBuffer(jsonByte)) if err != nil {fmt.Println(“err:”, err) return nil, err } for k, v := range headerMap {request.Header.Set(k, v) } //request.Header.Set(“Content-Type”, “application/json”) resp, err := ht.client.Do(request) if err != nil {fmt.Println(“err:”, err) return nil, err } defer resp.Body.Close() return ioutil.ReadAll(resp.Body) } 复制代码