gnet
gnet copied to clipboard
高并发下gnet服务端接收报文错乱
Describe the bug 在2000个连接的情况下,发送大数据,比如64k的数据,React函数里面的frame会偶发出现数据不正确的情况。
To Reproduce
Steps to reproduce the behavior:
最简单的客户端,和服务端。只在React函数部分增加检查数据一致性的操作
Expected behavior 发送客户端同样的数据,server端应该解析出一样的数据
Screenshots
正确情况下,前20位应该是 abcdefghijklmnopqrst
错误数据如下图
System Info (please complete the following information):
- OS (e.g. Ubuntu 18.04): Windows 10
- Go version (e.g. Go 1.13): Go 1.16.3
- gnet version (e.g. v1.0.0): v1.2.3
Additional context Add any other context about the problem here.
Thanks for opening a new issue. The team has been notified and will review it as soon as possible. For urgent issues and priority support, visit https://xscode.com/panjf2000/gnet
tcp是流式数据,需要处理粘包的情况
tcp是流式数据,需要处理粘包的情况
如果使用ants协程池,异步调用,怎么处理粘包和半包的情况呢
异步调用和TCP分包没关系,你有在 gnet 里实现自己编解码器吗?
Decode 里最后的 body 数据怎么没调用 binary.Read() ?
Decode 里最后的 body 数据怎么没调用 binary.Read() ?
Decode 里面 body 数据 直接通过第 17 行 dataSize, data := c.ReadN(bodyLen) 取得 data 了
if err := binary.Write(buffer, binary.LittleEndian, data); err != nil {
s := fmt.Sprintf("Pack data error , %v", err)
return nil, errors.New(s)
}
你这一段的目的是什么?
if err := binary.Write(buffer, binary.LittleEndian, data); err != nil { s := fmt.Sprintf("Pack data error , %v", err) return nil, errors.New(s) }
你这一段的目的是什么?
这段忘改了,和直接Write效果一样。大小端对 []byte 没作用。数据错乱不是编解码这边的问题,我测试过固定长度大数据在大并发下,编解码内部不做处理,直接返回固定长度的数据,也是有数据错乱情况。
你有没有在 linux 上测试过?是只有 windows 有这种情况还是 linux 也会出现?
你有没有在 linux 上测试过?是只有 windows 有这种情况还是 linux 也会出现?
Windows 10 和 WSL 下测试都会出现,mac 和纯 linux 主机下没测试过。
这个问题最近我也遇到了,目前处理方式是自定义一个byte数组,同步的方式拷贝过来,就没有出现数据重复了,如下:
demo代码片段:
func (h *UdpHandler) React(frame []byte, c gnet.Conn) (out []byte, action gnet.Action) {
data := make([]byte, len(frame))
copy(data, frame)
go func(frame []byte) {
time.Sleep(100 * time.Millisecond)
fmt.Printf("%p - %v \n", &frame, frame)
}(data)
return
}
嗯,如果只在 React 函数里处理数据而没有启动新的 goroutine 的话,则可以不用复制数据,否则的话则需要 copy 一份传给 goroutine,不然就有可能会有数据错乱的问题,因为 gnet 底层是共享同一段 []byte 的。 @nkypy 确认下是不是这个原因
pan神,遇到类似的问题,不过是客户端之间请求序号错乱了。。。而且只是用了框架自身的带的协议。
300个客户端,每次发送16KB,会出现几次错误
客户端是windows ide 服务端部署在linux上的
看起来你们俩都是参考的 custom_codec 这个例子,这个例子可能写的有点问题,这个是别人贡献的,我当时也没细看,我这两天抽空看看。
好的,pan神,我也感觉这个编解码有点不对劲,测试8kb,16kb都是偶现且会出现在两台机器上
嗯,如果只在 React 函数里处理数据而没有启动新的 goroutine 的话,则可以不用复制数据,否则的话则需要 copy 一份传给 goroutine,不然就有可能会有数据错乱的问题,因为 gnet 底层是共享同一段 []byte 的。 @nkypy 确认下是不是这个原因
之前我是没有起新的 goroutine 处理数据出现的问题。按照 lsm1998 的方法,copy数据,起新的 goroutine 处理数据,依旧存在问题。
请教下。Decode 返回的 []byte 有没有可能 被串改掉? // Decode ... func (cc *BuiltInFrameCodec) Decode(c Conn) ([]byte, error) { ....buf := c.Read() ....if len(buf) == 0 { ........return nil, nil ....} ....c.ResetBuffer() //2.如果这里释放了(bytebuffer.Put(c.byteBuffer) ) ....return buf, nil //3.如果byteBuffer 被其它 连接使用了,会不会造成 buf 的内容被改变? }
//=========================== func (c *conn) Read() []byte { ....if c.inboundBuffer.IsEmpty() { ........return c.buffer ....} ....c.byteBuffer = c.inboundBuffer.WithByteBuffer(c.buffer) ....return c.byteBuffer.Bytes() //1.这里返回的是 c.byteBuffer } func (c *conn) ResetBuffer() { ....c.buffer = c.buffer[:0] ....c.inboundBuffer.Reset() ....bytebuffer.Put(c.byteBuffer) ....c.byteBuffer = nil }
潘神,,解码demo有结果了吗?高并发始终会出现
Reactor之后数据变了,但是Reactor里面什么都没有做,就是out=frame return
补充下:Reactor()
最近太忙了,还没细看。
你这个就太诡异了,你在 React() 里也打印一下看看呢?
问题已解决,之前为了支持tls,把linux下的epoll代码去掉了,只用了windows代码,然后在linux测试出现这种并发问题。再次加上就没有了,但是带来了新的问题,epoll无法支持tls。。。潘神有tls计划吗?是否需要参考py bio或者c++版本实现tls拦截验证
你到底是在什么操作系统上跑出问题来的?
Linux 上用户自己控制好分包组包的逻辑应该不会有数据错乱的问题,现在 gnet
已经跑在不少线上环境了,一般来说不太可能出现这个问题。
windows的代码跑在linux上面出现的
红线处的两次shiftN,如果出现粘包,后面数据就读不出来了,第一次shiftn把协议头部分清掉了,下次再decode就没有协议头了
红线处的两次shiftN,如果出现粘包,后面数据就读不出来了,第一次shiftn把协议头部分清掉了,下次再decode就没有协议头了
你为啥要两次shiftN?正常一次就够了,只需要最后ShiftN(msgLen)
他说的是 @nkypy 的问题,这里的 codec 这么写的确有隐患。
这可能就破案了。