上次写完 websocket 服务端后,想着测试一下最大能承受多少连接,一试就试出来了bug
- 先总结一下吧
- 第一次:关闭管道后继续发送数据,,导致panic
close(ch) ch<-data
- 第二次:大量测试请求过来,因为一些坏连接而造成发送操作的阻塞
一个程序不断的发送信息
package main
import (
"golang.org/x/net/websocket"
"log"
"strconv"
"sync"
"sync/atomic"
"time"
)
var (
origin = "https://baidu.com"
url = "wss://*"
start = make(chan struct{})
// 计数
done int32
// 每个连接发送的信息数量 = msgNums + 1
msgNums = 50
wg sync.WaitGroup
)
func Worker(id int) {
ws, err := websocket.Dial(url, "", origin)
if err != nil {
log.Println("worker ", id, " dial fail:", err)
return
}
// 等待开始
<-start
send := 0
defer func() {
ws.Close()
log.Printf("worker %3d done, send:%3d \n", id, send)
wg.Done()
}()
for {
msg := []byte("{\"msg\":\"worker " + strconv.Itoa(id) + "\"}")
_, err := ws.Write(msg)
if err != nil {
return
}
send++
// 自定义数量
if send > msgNums {
// 结束全部任务
atomic.AddInt32(&done, 1)
return
}
time.Sleep(time.Second)
}
}
func main() {
// 建立连接
for i := range [70][0]int{} {
go Worker(i)
wg.Add(1)
}
// 开始发送
close(start)
// 等待发送任务完成
wg.Wait()
// 打印完成结果
log.Println("done:", done)
// 发送结束信息,可能不会收到
ws, err := websocket.Dial(url, "", origin)
if err != nil {
panic(err)
}
for range [5][0]int{} {
msg := []byte("end")
_, err := ws.Write(msg)
if err != nil {
panic(err)
}
time.Sleep(time.Millisecond * 500)
}
}
另一个程序不断接收信息(只开启一个连接)
package main
import (
"golang.org/x/net/websocket"
"io/ioutil"
"log"
"sync"
)
// 只有一个连接,不处理 err,不关闭
func Read(ws *websocket.Conn) (data []byte, ok bool) {
r, err := ws.NewFrameReader()
if err != nil {
return
}
fr, err := ws.HandleFrame(r)
if err != nil {
return
}
if fr == nil {
return
}
data, err = ioutil.ReadAll(fr)
if err != nil {
return
}
return data, true
}
var (
origin = "https://baidu.com"
url = "wss://*"
m sync.Map
msgNums = 51
readChan = make(chan string, 2000)
)
func Worker() {
ws, err := websocket.Dial(url, "", origin)
if err != nil {
log.Println("worker dial fail:", err)
return
}
exit := make(chan struct{})
go func() {
for {
select {
case s := <-readChan:
value, ok := m.Load(s)
if ok {
m.Store(s, value.(int)+1)
} else {
m.Store(s, 1)
}
case <-exit:
return
}
}
}()
for {
data, ok := Read(ws)
if ok {
s := string(data)
if s == "end" {
close(exit)
return
}
readChan <- s
}
}
}
func main() {
defer func() {
num := 0
all := 0
m.Range(func(key, value interface{}) bool {
log.Printf("%20s : %3d", key, value)
num++
if value == msgNums {
all++
}
return true
})
// 接收到的worker数量
log.Println("total worker: ", num)
// 全部接收数量
log.Println("all recv num: ", all)
}()
Worker()
}
- 最后,一般来说,只要连接建立,发送是没问题的,主要考虑的就是接收能力。
- 在阿里的单核服务器上,瓶颈在网络上,卡的死死的,每个连接每秒发送一次的情况下,可以有70 个连接左右,具体参数调整后会有差异,但作为学习和平时使用,100以内的连接数是完全可以胜任的