gnet icon indicating copy to clipboard operation
gnet copied to clipboard

用 gnet 做游戏网关,广播消息的场景

Open zklscut opened this issue 3 years ago • 5 comments

2000 个连接,每10 秒通过远端服务器向其他连接广播一条消息,大小 1K 左右 实际测试下来与直接转发效率差了 25%左右 后来也使用了 https://github.com/calbot/gnet.git来管理gnet与服务器的连接,发现性能依旧是降低的 不太适合这个场景?还是使用有问题

func (es *echoServer) React(frame []byte, c gnet.Conn) (out []byte, action gnet.Action) {
	data := append([]byte{}, frame...)
	_ = es.pool.Submit(func() {
		s, ok := serverMap.Load(c.RemoteAddr().String())
		if ok {
			serverConn := s.(net.Conn)
			serverConn.Write(data)
		}
	})

	return
}
func (es *echoServer) OnOpened(c gnet.Conn) (out []byte, action gnet.Action) {
	serverConn, _ := net.Dial("tcp", serverAddr)
	serverMap.Store(c.RemoteAddr().String(), serverConn)

	go func() {
		b := make([]byte, 2048)
		for {
			size, err := serverConn.Read(b)
			if err != nil {
				break
			}
			c.AsyncWrite(b[0:size])
		}
	}()
	return
}
func test() {
	l, _ := net.Listen("tcp", "127.0.0.1:6060")
	defer l.Close()
	go func() {
		for {
			clientConn, _ := l.Accept()
			serverConn, _ := net.Dial("tcp", "127.0.0.1:6061")
			go func() {
				b := make([]byte, 2048)
				for {
					size, err := serverConn.Read(b)
					if err != nil {
						break
					}
					if size > 0 {
						clientConn.Write(b[0:size])
					}
				}
			}()

			go func() {
				b := make([]byte, 2048)
				for {
					size, err := clientConn.Read(b)
					if err != nil {
						break
					}
					if size > 0 {
						serverConn.Write(b[0:size])
					}
				}
			}()
		}
	}()
}

zklscut avatar Jul 28 '21 09:07 zklscut

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

xscode-auto-reply[bot] avatar Jul 28 '21 09:07 xscode-auto-reply[bot]

gnet 哪个版本?还有为什么要用 goroutine pool? React() 直接写不就行了?

panjf2000 avatar Jul 28 '21 14:07 panjf2000

你这种用法只用了 gnet 的异步任务队列的功能,gnet 管理的每一个 socket 要依赖于另外一个 socket 的响应,所以每一个 gnet 的 socket 回写数据的时候是先放到异步队列,然后通过系统调用,唤醒 epoll 所在的线程去 Write 数据,当然不如用标准库直接 Write 了。

gnet 不太适合你这种场景。

panjf2000 avatar Jul 28 '21 14:07 panjf2000

你这种用法只用了 gnet 的异步任务队列的功能,gnet 管理的每一个 socket 要依赖于另外一个 socket 的响应,所以每一个 gnet 的 socket 回写数据的时候是先放到异步队列,然后通过系统调用,唤醒 epoll,当然不如用标准库直接 Write 了。

gnet 不太适合你这种场景。

谢谢解答,另外关于这种场景有什么优化建议么?对应的项目是游戏内的战斗广播,1000 人集中在一个点上互相广播消息。包的大小从500B 到 10K 不等,gnet在这里只负责转发两侧的消息。 尝试了几种优化方案都不太理想。

zklscut avatar Jul 29 '21 02:07 zklscut

这类型优化感觉得看具体的应用场景了, 举例来说

如果是MMOG类的游戏, 一个服里几千人, 但实际上的互相广播, 只有视距内的玩家需要做到互相广播, 这样的话, 广播范围会控制在几十到几百个人内.

主要想法有2种,一种是分区广播, 减少广播域, 一种是延迟广播, 优先满足重点区域, 然后再广播次要区域. 

------------------ 原始邮件 ------------------ 发件人: "panjf2000/gnet" @.>; 发送时间: 2021年7月29日(星期四) 上午10:40 @.>; @.***>; 主题: Re: [panjf2000/gnet] 使用gnet做网关转发时,性能不如直接创建Groutine处理? (#236)

你这种用法只用了 gnet 的异步任务队列的功能,gnet 管理的每一个 socket 要依赖于另外一个 socket 的响应,所以每一个 gnet 的 socket 回写数据的时候是先放到异步队列,然后通过系统调用,唤醒 epoll,当然不如用标准库直接 Write 了。

gnet 不太适合你这种场景。

谢谢解答,另外关于这种场景有什么优化建议么?对应的项目是游戏内的战斗广播,1000 人集中在一个点上互相广播消息。包的大小从500B 到 10K 不等。 尝试了几种优化方案都不太理想。

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or unsubscribe.

Chairou avatar Jul 29 '21 07:07 Chairou