SendBuffMsg存在安全问题.
c.msgBuffChan <- msg
//在大并发高负载的情况下 经常因为这句崩溃,原因是向一个关闭的chan写入数据,
//可能是在“将data封包,并且发送”的时候chan被其他携程关闭了 所有在发送前最后再检查一下最好!
func (c *Connection) SendBuffMsg(msgId uint32, data []byte) error { if c.isClosed == true { return errors.New("Connection closed when send buff msg") } //将data封包,并且发送 dp := NewDataPack() msg, err := dp.Pack(NewMsgPackage(msgId, data)) if err != nil { fmt.Println("Pack error msg id = ", msgId) return errors.New("Pack error msg ") }
//写回客户端
c.msgBuffChan <- msg
return nil
}
错误日志:
---> CallOnConnStart.... [Writer Goroutine is running] [Reader Goroutine is running] read msg head error EOF Conn Stop()...ConnID = 156 ---> CallOnConnStop.... Send Buff Data error:, write tcp4 172.21.0.15:7777->39.189.45.248:14870: use of closed network connection Conn Writer exit 39.189.45.248:14870 [conn Writer exit!] connection Remove ConnID= 156 successfully: conn num = 0 39.189.45.248:14870 [conn Reader exit!] panic: send on closed channel
goroutine 36 [running]: github.com/aceld/zinx/znet.(*Connection).SendBuffMsg(0xc0000d00e0, 0x1f4, 0xc0003f9400, 0x95, 0xa0, 0x0, 0x0) /Users/jamie/go/pkg/mod/github.com/aceld/[email protected]/znet/connection.go:226 +0x1ec YmServer/tools.Response(0xac40c0, 0xc000524a20, 0x1000001f4, 0x9fc41e, 0x2, 0xc000515470) /Users/jamie/go/src/YmServer/tools/toos.go:35 +0x10d YmServer/controller.(*GetMyGameProxyRouter).Handle(0xe84c88, 0xac40c0, 0xc000524a20) /Users/jamie/go/src/YmServer/controller/my_game.go:72 +0x517 github.com/aceld/zinx/znet.(*MsgHandle).DoMsgHandler(0xc000217080, 0xac40c0, 0xc000524a20) /Users/jamie/go/pkg/mod/github.com/aceld/[email protected]/znet/msghandler.go:47 +0xe4 github.com/aceld/zinx/znet.(*MsgHandle).StartOneWorker(0xc000217080, 0x6, 0xc000234720) /Users/jamie/go/pkg/mod/github.com/aceld/[email protected]/znet/msghandler.go:70 +0x103 created by github.com/aceld/zinx/znet.(*MsgHandle).StartWorkerPool /Users/jamie/go/pkg/mod/github.com/aceld/[email protected]/znet/msghandler.go:83 +0x50
压测的时候每次都要panic, 加了closed判断都没用啊, 还有msgChan好像都没有close, 如果close了,也会panic
c.msgBuffChan <- msg //在大并发高负载的情况下 经常因为这句崩溃,原因是向一个关闭的chan写入数据, //可能是在“将data封包,并且发送”的时候chan被其他携程关闭了 所有在发送前最后再检查一下最好!
func (c *Connection) SendBuffMsg(msgId uint32, data []byte) error { if c.isClosed == true { return errors.New("Connection closed when send buff msg") } //将data封包,并且发送 dp := NewDataPack() msg, err := dp.Pack(NewMsgPackage(msgId, data)) if err != nil { fmt.Println("Pack error msg id = ", msgId) return errors.New("Pack error msg ") }
//写回客户端 c.msgBuffChan <- msg return nil}
错误日志:
---> CallOnConnStart.... [Writer Goroutine is running] [Reader Goroutine is running] read msg head error EOF Conn Stop()...ConnID = 156 ---> CallOnConnStop.... Send Buff Data error:, write tcp4 172.21.0.15:7777->39.189.45.248:14870: use of closed network connection Conn Writer exit 39.189.45.248:14870 [conn Writer exit!] connection Remove ConnID= 156 successfully: conn num = 0 39.189.45.248:14870 [conn Reader exit!] panic: send on closed channel
goroutine 36 [running]: github.com/aceld/zinx/znet.(*Connection).SendBuffMsg(0xc0000d00e0, 0x1f4, 0xc0003f9400, 0x95, 0xa0, 0x0, 0x0) /Users/jamie/go/pkg/mod/github.com/aceld/[email protected]/znet/connection.go:226 +0x1ec YmServer/tools.Response(0xac40c0, 0xc000524a20, 0x1000001f4, 0x9fc41e, 0x2, 0xc000515470) /Users/jamie/go/src/YmServer/tools/toos.go:35 +0x10d YmServer/controller.(*GetMyGameProxyRouter).Handle(0xe84c88, 0xac40c0, 0xc000524a20) /Users/jamie/go/src/YmServer/controller/my_game.go:72 +0x517 github.com/aceld/zinx/znet.(*MsgHandle).DoMsgHandler(0xc000217080, 0xac40c0, 0xc000524a20) /Users/jamie/go/pkg/mod/github.com/aceld/[email protected]/znet/msghandler.go:47 +0xe4 github.com/aceld/zinx/znet.(*MsgHandle).StartOneWorker(0xc000217080, 0x6, 0xc000234720) /Users/jamie/go/pkg/mod/github.com/aceld/[email protected]/znet/msghandler.go:70 +0x103 created by github.com/aceld/zinx/znet.(*MsgHandle).StartWorkerPool /Users/jamie/go/pkg/mod/github.com/aceld/[email protected]/znet/msghandler.go:83 +0x50
我也是想来问这个,就看到你的提问了;看起来只能加锁,但是不知道对大并发的情况性能影响有多大
func (c *Conn) Send(msgID uint32, data []byte) error {
if !c.isClosed {
pack := NewPack()
if msg, err := pack.Pack(NewMsg(msgID, data)); err != nil {
log.Println("package pack err:", err)
return err
} else {
select {
case <-c.exitChan:
return errors.New("conn is closed")
default:
c.msgChan <- msg
}
}
return nil
}
return errors.New("conn closed when send message")
}
先判断连接停止的chan是否已关闭,已关闭则不做处理,没有关闭则向msgChan投递消息。这样就不会panic了。