参考:

deepseek、豆包

 

一 TCP和UDP区别

二 Webscoket是基于TCP还是UDP?

三 TCP的三次握手、四次挥手是什么意思?

四 怎么让websocket用udp?

五 帧同步和状态同步比较

 

一 TCP和UDP区别?

1 连接方式

TCP:面向连接,通信前三次握手建立连接,结束后四次挥手释放连接。

UDP:无连接,直接发送数据,无需预先建立连接。

 

2 可靠性

TCP:提供可靠传输,通过确认应答、超时重传、流量控制、拥塞控制等机制确保数据不丢失、不重复、按序到达。

UDP:不可靠传输,不保证数据到达顺序或是否丢失,无重传机制。

 

3 速度效率

TCP:传输速度慢,头部大(至少20字节),延迟较高。

UDP:无额外控制机制,头部小(仅8字节),传输更快,实时性更好。

 

4 流量控制

TCP:动态调整发送速率(滑动窗口、慢启动、拥塞避免等),避免网络过载。

UDP:无流量控制,可能发送过快导致丢包、网络拥塞。

 

5 应用场景:

TCP:网页浏览(HTTP)、文件传输(FTP)、电子邮件(SMTP)

UDP:视频会议、在线游戏、语音通话、直播流媒体

 

总结:

TCP可靠,但是效率低。

UDP不可靠,但是效率高。

 

二 Websocket是基于TCP还是UDP?

websocket是基于TCP的,选择TCP的理由是websocket用于双向通信,例如聊天、游戏等,需要确保消息不丢失、按序到达。

而UDP不保证消息完整性,在视频中丢帧可以,但是聊天消息丢失是不可接受的。

 

三 TCP的三次握手、四次挥手是什么意思?

三次握手

第一次握手:客户端告诉服务端我要连接你

第二次握手:服务端告诉客户端我收到了你的请求

第三次握手:客户端告诉服务端我收到了你的回复

通过三次握手,确认双方收发能力正常。

再仔细一看,确实通过三次握手,客户端收和发了一次,服务端也收和发了一次。

 

四次挥手

第一次挥手:客户端告诉服务端我不发数据了。

第二次挥手:服务端告诉客户端我收到了你不发数据的消息。

第三次挥手:服务端告诉客户端我也不发送数据了。

第四次挥手:客户端告诉服务端我收到了你不发数据的消息。

通过四次挥手,双方确认数据传输完毕,可以关闭连接。

 

为什么第二和第三次挥手不能合并?

因为服务端发送第二次挥手后还可能继续发送数据,如何合并了服务端就会立即关闭,未发送的数据会丢失。

 

那么为什么服务端不发送完数据后,再合并发送第二次和第三次挥手?

理论上服务端没有数据要发了,是可以合并第二次和第三次挥手,但是大多数操作系统默认不会合并,是严格执行四次挥手。

 

 

四 怎么让websocket用udp?

websocket是基于TCP的,无法直接使用UDP。

web可以用websocket模拟UDP,实际还是TCP。原生可以使用真正UDP,底层C++/Java实现通信,然后通过JS接口调用。

 

五 帧同步和状态同步比较

帧同步

1. 所有客户端上传操作指令。

2. 服务端收到所有客户端指令,然后广播给所有客户端。

3. 每个客户端收到广播的操作指令,计算游戏结果。

 

客户端如何保证同步的?

每个客户端在相同逻辑帧 + 执行相同的操作指令 = 相同的计算结果。

例如第一个逻辑帧A移动,客户端ABC都执行移动指令,那么客户端ABC上都会得到A移动的计算结果,A移动了10像素。

第二个逻辑帧C放技能,客户端ABC都执行放技能指令,那么客户端ABC上都会得到C放技能的计算结果,C放了一个火球术。

第三个逻辑帧B自杀了,客户端ABC都执行B自杀指令,那么客户端ABC上都会得到B自杀的计算结果,B死亡角色离开了游戏。

第N个逻辑帧,客户端ABC执行相同N个指令,都会得到相同的计算结果。

 

状态同步

1. 所有客户端上传操作指令。

2. 服务端计算结果,生成权威状态(玩家坐标、血量),并将结果广播给所有客户端。

3. 客户端根据服务端状态更新本地表现。

 

状态同步是服务端计算逻辑,所以计算结果是唯一的。

 

帧同步和状态同步区别

                                帧同步                                  状态同步

同步对象           操作指令(移动、技能)              游戏状态(玩家位置、血量、技能)

传输内容           较小                                          较大

逻辑计算           客户端计算逻辑                        服务端计算逻辑

典型游戏           王者荣耀                                  魔兽世界、CS

 

帧同步是客户端计算逻辑,那么玩家可以修改本地数据,怎么防止作弊呢?

因为逻辑在客户端,所以没法彻底杜绝作弊,例如风灵月影,黑神话、鬼谷八荒啥都能改。

 

防止作弊的一些方法

1 操作指令校验:服务端进行操作校验,例如移动速度是否超出上限、技能释放是否符合冷却时间等。

2 关键帧校验:所有客户端上传游戏状态,哪个客户端数据和其它客户端不一致,就判定为作弊。

3 延迟追惩:服务端保存所有操作指令,然后模拟实现游戏过程,再对比客户端上传的结果。

4 客户端混淆:混淆代码,增加逆向难度。

5 内存加密:对关键变量保存时进行加密,例如攻击力进行异或后再保存。

 

deepseek给的一些案例,服务端校验移动合法性:

// 服务端:校验移动合法性
bool ValidateMovement(int playerId, Vector2 newPos, int currentFrame) {
    // 获取上一帧位置
    Vector2 lastPos = GetPlayerPosition(playerId, currentFrame - 1);
    
    // 计算最大允许移动距离(速度*帧间隔)
    float maxDistance = playerSpeed * frameInterval;
    
    // 实际移动距离是否合法
    if (Vector2.Distance(lastPos, newPos) > maxDistance * 1.2f) { // 允许20%误差
        LogCheat(playerId, "Speed Hack");
        return false;
    }
    return true;
}

  

预测和回滚

客户端为了玩家体验,减少延迟感,会先行进行预测,提前模拟执行操作指令,例如移动,射击。

但是预测和服务端不一致时,服务端会推翻客户端的计算结果,客户端需要修正状态。

例如玩CS延迟时,虽然你一直按着前跑,但是你的角色会不停被拉回原地。

 

那么如何优雅的回滚状态?

1 移动不一致:插值移动,从错误位置平滑移动到正确位置。但是实际上玩英雄联盟、球球大作战之类,太卡的时候,仍会有移动忽快忽慢,瞬移。

2 攻击判断不一致:客户端命中,服务端未命中。客户端先行表现射击,命中判定等待服务端返回。例如CS里你对着某人开枪怎么都打不死,就是服务端判定未命中。

3 回滚网络补偿:回滚到正确帧,然后再继续

4 预测容错:客户端允许存在小误差,例如位置偏移小于20像素 不纠正。

 

不同类型游戏的处理侧重

 

我觉得这个回滚很麻烦,所以还是客户端可以先行表现一些动作,例如射击、施法前摇等,具体的计算逻辑还是等服务端返回再说吧。

 

设计方案

竞技游戏:服务端权威,公平性>流畅性

休闲游戏:客户端预测,流畅性>公平性

说白了就是严谨点的游戏服务器跑逻辑,防止作弊,卡的话自己掏钱装好点宽带。

休闲点的游戏客户端跑逻辑,优先保证玩家流程体验,同时又减少了开发成本。

 

posted on 2025-07-11 19:16  gamedaybyday  阅读(62)  评论(0)    收藏  举报