高维思考,低维行动。
之前的文章中,我们谈到了CS通信协议中有关序列化的话题。今天我们继续,谈谈通信连接的选型。
连接类型
在游戏服务器通信开发时,经常要面对长连接、短连接选型问题。在游戏中常用的连接类型有以下这些:
- 长连接
- tcp 连接
- udp 连接
- rudp 可靠udp连接
- 短连接
- http1
- http2
- quic/http3
短连接使用场景
短连接通常在以下几种游戏开发场景中使用:
- 单机游戏或小型游戏。
对于小型游戏或单机游戏而言,短连接可以用于与服务器进行一次性的通信,交互比较少。
一些单机游戏只需要在游戏完成后上传分数或者拉取排行榜,这种交互的频率非常低,服务器完全没有必要维持一个和客户端的长期连接,占用资源。
还有一些社交游戏,比如早期的偷菜游戏,玩家的操作也不太多,服务器搭建一个web框架接受客户端的 http 请求即可。
需要注意的是,最常用的是 http1.1 协议,http1.1 的语义规范上只支持客户端主动的发送 request 到服务器,服务器返回 response 给客户端;如果服务器想推送消息给客户端,是没法做到的。
服务器主动推送消息给客户端往往是基于实时性的考虑:某一个玩家或场景的信息如果发生改变,要第一时间广播推送给所有相关的多个客户端。
http2 新规范的提出解决了这个问题,它的一个重要改进就是支持了服务器 -> 客户端的主动推送。
再后来 quic/http3 的标准又被提出,http3 相对于 http1.1 和 http2 效率更高,底层放弃了 tcp 而改用 udp,支持完全的并发请求,对协议包的顺序没有要求。当然,http2 和 http3 在游戏行业还没有得到全面的普及,大部分业务场景还是使用 http1.1 的。
- 游戏资源下载。
游戏的客户端包或者更新资源一般都会放置在专用的下载平台如 cdn 供用户下载,这种情况下客户端发起 http 请求来拉取资源。
- 游戏平台认证和登录。
短连接可以用于处理玩家的认证和登录过程。当玩家启动游戏时,客户端可以通过短连接与平台服务器进行身份验证,并获取登录令牌(token)或会话密钥。
由于登录(包括拉取游戏服务器列表)一般也是一次性行为,所以这部分的逻辑也通常采用 http 协议来实现。
平台登录完成之后,就可以选择服务器并进入游戏了。
在新游戏公测时,由于玩家较多,很多游戏还支持了排队功能。这部分功能,类似地,也可以用 http 协议来实现,比如定期发起 http 请求拉取排队人数。
- 游戏匹配和大厅。
很多棋牌类的游戏以及其他开房间的游戏(如吃鸡、moba类),有专门的游戏大厅服务器,在游戏匹配和大厅系统中,短连接可以用于处理玩家之间的基本通信和信息交换。例如,玩家可以使用短连接与服务器进行匹配请求、获取游戏列表、发送和接收聊天消息等。
长连接使用场景
长连接是游戏中使用最广泛的一种连接形式。需要强调的是,严格意义上说 udp 以及基于 udp 的可靠 udp (rudp)并没有连接的概念,但是为了方便,我们还是将这二者归入长连接的范畴加以讨论和对比。
在通常的互联网应用中,一般是比较偏重内容的,用户和服务器的交互并不会太频繁。如登录购物网站或者浏览新闻推送,往往拉取到需要的内容后,用户需要花时间消化该部分内容;而游戏则非常不一样,要么玩家在不停的做任务领取奖励,要么在关卡里战斗、打牌等,要么在聊天频道聊天,交互非常频繁。
正是由于游戏业务的交互特性,游戏不能只用互联网应用中常用的http 协议,要使用长连接来传送大量的操作信息,并接受服务器的实时推送。
在长连接中,tcp 是最常用的一种。基本所有的处理实时状态同步的需求都可以通过tcp来传输。TCP提供可靠的、有序的数据传输,适用于需要确保数据完整性和可靠性的场景。
基于 tcp ,传输游戏业务自己自定义的应用层的包体。
在游戏中,虽然大部分业务都可以基于 tcp 来传输,但是还是部分场景有些特殊。
比如一些游戏中需要加入语音聊天、实时位置更新等,这个时候数据量比较大,对延迟和速度的要求比较高。
需要了解的是,tcp 在实现的时候提供了不丢包、前后顺序的保证,在网络带宽资源利用率、对网络异常(如拥塞)的处理速度方面采用了中规中矩的处理策略;相对应的,udp 并没有限制对于网络带宽的激进使用,在特定业务,数据量的情况下使用 udp 可以最大限度的利用带宽,降低延迟。
当然 udp 可能丢包,没有可靠性的保证,其顺序也没有保证,如果业务需要这些,就需要在应用层基于 udp 封装类似 tcp 的可靠性、顺序性机制。
例如,很多实时动作游戏对操作的响应要求极高,一点点的延迟就会造成游戏体验的巨大差异。这种游戏中的战斗一般舍弃通常的状态同步,改用帧同步来控制延迟。
这就是可靠udp(reliable udp)的应用场景。可靠udp 结合了UDP的实时性和TCP的可靠性,通过应用层实现数据包的确认和重传机制,以保证数据的可靠性。同时实时性、可靠性的设置从内核态转移到应用态,可以更灵活的控制参数。
在网络环境比较差的情况下,比如移动网络覆盖不到的区域、或者其他可能导致移动网络切换的场景,可靠 udp 表现的非常优秀。
可靠UDP(RUDP)有很多实现,如国人开发的开源 KCP 项目、google 的 Quic,虚幻引擎 UE 也自己实现了一套基于 UDP的可靠连接,用于实现 RPC 通信。
这里还要指出,很多企业、运营商和组织会对 53端口(DNS)以外的 UDP 流量(包括基于udp的可靠udp流量)进行拦截或者限流,因为这些流量近来常被滥用于攻击。特别是一些现有的 UDP 协议和实现易受放大攻击(amplification attack)威胁,攻击者可以控制无辜的主机向受害者投放发送大量的流量。
在实际应用时,往往需要综合应用:
比如客户端资源下载、平台登录时,采用 http 协议。进入游戏后,主要逻辑游戏采用 tcp;在实时性要求较高的战斗场景启用可靠udp,如果 udp 因为运营商限制,退而求其次改用 tcp。
作者:我是码财小子,会点编程代码,懂些投资理财;期待你的关注,不要错过我后续的文章更新。