
最近在做一个基于虚幻引擎 5.8 的联机 Demo踩了不少坑服务端打包出来在局域网里能进换到云服务器就连不上客户端日志堆了一堆信息却分不清哪条是客户端打的、哪条是服务器打的后来还遇到打包后的专用服务器日志文件不刷新启动参数没带全导致静默崩溃等问题。网上资料比较零散所以我把整套流程整理成一篇可以照着操作的教程从最基础的联机概念开始到打包服务器端、部署、客户端连接再到用 UE_LOG 打印调试信息一步步走通。本文适合刚接触 UE 联机开发的读者也适合已经能跑单机项目、但第一次接触 Dedicated Server 打包部署的开发者。学完之后你可以独立完成一个 UE5.8 联机项目的服务端打包、私有服务器部署、客户端连接和日志排查工作。1. 虚幻引擎 5.8 联机背后的核心概念1.1 什么是 Listen Server 和 Dedicated Server在 UE 中最常见的联机架构有两种。第一种叫Listen Server监听服务器。这种模式下创建房间的玩家本身既是客户端又充当服务器。其他玩家连到房主机器上房主通常拥有最高权限P2P 联机、局域网联机很多都采用这种方案。优点是部署简单一个游戏进程就能开房缺点也很明显房主退出整个游戏会话结束网络延迟也受房主机器配置影响。局域网开黑、朋友小规模联机比较适合。第二种叫Dedicated Server专用服务器通常缩写为 DS。DS 是一个不渲染画面、只处理游戏逻辑和网络同步的独立服务器进程不参与战斗表现也不会在玩家本地显示画面。玩家客户端连接的是这个 DS。它的优势是稳定性强不受房主电脑影响玩家退出不影响会话适合正式运营、排行榜、持久化存档等场景。本文要讲的打包部署就是围绕 Dedicated Server 展开的。需要注意的是DS 运行时不创建完整游戏世界画面所以很多客户端绘制、UI、特效相关代码需要在服务器端跳过否则会造成大量无效开销甚至崩溃。1.2 为什么需要单独打包服务器端很多新手会问UE 编辑器里点击 Play 不是就能联机了吗编辑器里的 Play 联机只适合开发调试。生产环境里服务端需要跑在没有显卡、没有显示器的云主机或专用机房上这时候需要去掉渲染、音频等客户端组件减小体积。不依赖 GPU 资源减少服务器成本。提供更稳定的网络连接避免房主机器波动影响所有玩家。配合 CI/CD、Docker 等部署方式实现自动化发布。所以 UE 提供了BuildCookRun打包命令可以单独生成一个不带客户端的服务器二进制包。我们后续需要把-server参数传给打包工具。1.3 服务端与客户端的网络角色在 UE 联机中有几个高频出现的术语Server拥有权威逻辑的一方所有重要 gameplay 状态都以服务器数据为准。Client玩家本地进程负责输入采集、表现渲染和预测。Authority权威拥有某个 Actor 控制权的连接端。通常服务器端对大多数 Actor 拥有 Authority。Replication复制通过网络将 Actor 属性、RPC 从服务器同步到客户端或从客户端发送到服务器。在调试联机问题时首先要养成的习惯是先判断当前日志属于哪个进程。比如服务端收到的消息是HasAuthority()为 true客户端可能为 false同一段代码在 DS 和客户端上走的分支完全不同。1.4 常见的联机调试手段UE5.8 自带的调试手段很丰富UE_LOG输出日志到 Output Log 和文件。GEngine-AddOnScreenDebugMessage在客户端屏幕上绘制调试文本。stat net、stat fps、netconnection等控制台命令查看网络状态。-log、-LogCmds启动参数控制日志输出级别。SaveGame与存档验证服务器数据是否持久化。本文重点把UE_LOG和 AddOnScreenDebugMessage 结合起来让服务端和客户端的调试信息都能清晰区分。2. 环境准备与版本说明2.1 开发机配置建议UE 5.x 对硬件要求比较高开发机建议至少 16GB 内存、独立显卡系统盘剩余空间不低于 100GB。因为 UE5.8 的引擎下载、Cook 缓存、打包输出都会占用大量空间。本文实操环境如下操作系统Windows 11 专业版开发机Ubuntu 22.04云服务器可选。虚幻引擎Unreal Engine 5.8。编译器Visual Studio 2022勾选“使用 C 的游戏开发”。示例项目使用 UE5.8 自带的 Third Person 模板创建项目命名为MyProject。部署服务器局域网 Windows 主机或云服务器配置至少 2 核 4GB。如果你的版本是 UE5.3 / 5.4 / 5.5后续菜单路径和命令行参数大体一致个别界面名称有差异时请以你的实际版本为准。2.2 创建基础项目打开 Epic Games Launcher在虚幻引擎标签页启动 UE5.8。选择 Third Person 模板项目名设置为MyProject目标平台选择桌面平台项目路径建议放在D:\Projects\下避免中文或特殊符号路径。创建完成后用 Visual Studio 打开MyProject.sln确认解决方案能正常编译通过。这一步极为重要后面添加 C 代码、打包服务器端都需要先生成一个新的解决方案。2.3 添加联机必需的 C 类为了演示服务器端的日志输出我们先创建几个 C 类。在 UE 编辑器中选择Tools-New C Class父类选择GameModeBase类名MyProjectGameMode。父类选择PlayerController类名MyPlayerController。如果后续需要自定义角色可以再创建一个继承自Character的类。创建完成后编译一次项目确保 C 代码能正确链接。3. 虚幻引擎 5.8 联机配置与调试信息机制3.1 设置默认 GameMode要让打包后的服务器端使用我们自定义的 GameMode需要在项目设置里指定。打开Config/DefaultEngine.ini添加以下内容[/Script/EngineSettings.GameMapsSettings] GlobalDefaultGameMode/Script/MyProject.MyProjectGameMode GameDefaultMap/Game/ThirdPerson/Maps/ThirdPersonMap ServerDefaultMap/Game/ThirdPerson/Maps/ThirdPersonMap其中GlobalDefaultGameMode默认 GameMode所有地图都会使用该 GameMode除非地图自身覆盖。GameDefaultMap客户端启动时进入的地图。ServerDefaultMap专用服务器启动时加载的地图。DS 启动时会优先读取这个地图所以必须写对地图路径。你可以从编辑器右上角的 Map 路径里复制例如/Game/ThirdPerson/Maps/ThirdPersonMap。3.2 配置网络端口和帧率UE 的默认网络端口是 7777端口冲突或防火墙限制是最常见的联机失败原因。在DefaultEngine.ini中可以通过 Engine 子配置调整[/Script/OnlineSubsystemUtils.IpNetDriver] NetServerMaxTickRate60 MaxClientRate0 DefaultPort7777NetServerMaxTickRate服务器每秒网络更新次数60 对于多数项目足够竞技类可提高到 120。MaxClientRate客户端最大带宽限制0 表示不限制。DefaultPort默认监听端口。如果使用 Steam 联机还需要配置 OnlineSubsystem但本文重点是原生 IP 联机局域网或公网直连不依赖 Steam。3.3 UE_LOG 的基础使用UE_LOG是 UE 中最常用的日志宏格式如下UE_LOG(LogTemp, Warning, TEXT(This is a message: %s), *SomeFString);参数说明LogTemp日志分类可以自定义。Warning日志级别常见有Verbose、Log、Display、Warning、Error。Warning 和 Error 会以醒目的颜色显示在 Output Log 中日常调试建议用Log或Display。TEXT()UE 的宽字符字符串宏C 里写字符串时几乎都要带。格式化字符串%s对应TCHAR*%d对应整数%f对应浮点数。自定义日志分类示例在头文件中声明DECLARE_LOG_CATEGORY_EXTERN(LogMyProject, Log, All);在 cpp 文件中定义DEFINE_LOG_CATEGORY(LogMyProject);之后就可以使用UE_LOG(LogMyProject, Warning, TEXT(Hello from MyProject.));这样做的好处是打包后的服务器日志里可以按分类过滤比如只显示LogMyProject开头的日志排查效率会比混在 LogTemp 里高很多。3.4 在屏幕上打印调试信息UE_LOG输出到日志文件但如果我们希望客户端玩家或开发者在画面上直接看到信息可以用GEngine-AddOnScreenDebugMessage( -1, // Key-1 表示每次都新建一条 5.0f, // 显示时长 FColor::Green, // 颜色 TEXT(This is a debug message) );这里要注意该函数只能在有渲染画面的进程中调用。如果服务器端是 Dedicated Server它不渲染画面调用不会报错但没有任何意义。调试联机时常见做法是服务端用UE_LOG输出日志客户端同时用UE_LOG和AddOnScreenDebugMessage输出本地状态。3.5 区分服务器和客户端的日志Dedicated Server 和客户端是两个不同进程不会共享同一个 Output Log。为了排查问题我们需要让每条日志自带进程身份标记。推荐两种做法在日志文本里手动加前缀比如服务端日志统一以[SERVER]开头客户端日志以[CLIENT]开头。在启动参数里传入一个自定义标识比如-ClientTagAlice然后用FCommandLine::Get()读取拼接到日志中。第二种方法在多人联机调试时特别实用。例如启动服务器时传入-ServerTagLocalDS客户端传入-ClientTagClient1日志内容就会变成LogMyProject: [LocalDS] Server receives RPC from Player1 LogMyProject: [Client1] Local player controller spawned4. 完整实战打包服务器端并部署4.1 编写联机测试代码我们先写几个关键类用来验证服务端和客户端的日志。1. 自定义 GameMode编辑MyProjectGameMode.h#pragma once #include CoreMinimal.h #include GameFramework/GameModeBase.h #include MyProjectGameMode.generated.h UCLASS() class MYPROJECT_API AMyProjectGameMode : public AGameModeBase { GENERATED_BODY() public: AMyProjectGameMode(); virtual void PostLogin(APlayerController* NewPlayer) override; virtual void Logout(AController* Exiting) override; };编辑MyProjectGameMode.cpp#include MyProjectGameMode.h #include MyPlayerController.h AMyProjectGameMode::AMyProjectGameMode() { PlayerControllerClass AMyPlayerController::StaticClass(); } void AMyProjectGameMode::PostLogin(APlayerController* NewPlayer) { Super::PostLogin(NewPlayer); if (NewPlayer) { UE_LOG(LogTemp, Warning, TEXT([SERVER] Player joined: %s), *NewPlayer-GetName()); } } void AMyProjectGameMode::Logout(AController* Exiting) { Super::Logout(Exiting); if (Exiting) { UE_LOG(LogTemp, Warning, TEXT([SERVER] Player left: %s), *Exiting-GetName()); } }PostLogin和Logout是 GameMode 中的虚拟函数当有玩家连入或断开时服务器端会调用它们。这是观察连接状态最直接的入口。2. 自定义 PlayerController编辑MyPlayerController.h#pragma once #include CoreMinimal.h #include GameFramework/PlayerController.h #include MyPlayerController.generated.h UCLASS() class MYPROJECT_API AMyPlayerController : public APlayerController { GENERATED_BODY() public: virtual void BeginPlay() override; UFUNCTION(Server, Reliable, WithValidation) void ServerSendMessage(const FString Message); virtual void SendMessageToServer(const FString Message); };编辑MyPlayerController.cpp#include MyPlayerController.h #include Engine/Engine.h void AMyPlayerController::BeginPlay() { Super::BeginPlay(); if (IsLocalController()) { UE_LOG(LogTemp, Log, TEXT([CLIENT] Local PlayerController BeginPlay: %s), *GetName()); } if (HasAuthority()) { UE_LOG(LogTemp, Log, TEXT([SERVER] PlayerController has authority: %s), *GetName()); } } void AMyPlayerController::SendMessageToServer(const FString Message) { ServerSendMessage(Message); } bool AMyPlayerController::ServerSendMessage_Validate(const FString Message) { // 校验逻辑消息非空且长度不超过128防止恶意玩家发送超长内容 return Message.Len() 0 Message.Len() 128; } void AMyPlayerController::ServerSendMessage_Implementation(const FString Message) { UE_LOG(LogTemp, Warning, TEXT([SERVER] Received message: %s, from player: %s), *Message, *GetName()); }这里的关键是UFUNCTION(Server, Reliable, WithValidation)它声明了一个从客户端调用、在服务器端执行的 RPC。Server调用发生在客户端实际执行在服务器端。Reliable可靠消息保证到达适用于登录、聊天等关键数据。WithValidation启用_Validate校验函数服务端会先校验再执行推荐所有客户端到服务器的 RPC 都加上避免恶意客户端利用协议漏洞。3. 测试 RPC 调用在某个客户端输入事件中调用void AMyPlayerController::SendMessageToServer(const FString Message) { if (IsLocalController()) { UE_LOG(LogTemp, Log, TEXT([CLIENT] Sending message to server: %s), *Message); ServerSendMessage(Message); } }当客户端执行SendMessageToServer时本地日志会先输出[CLIENT] Sending message...随后服务器端日志出现[SERVER] Received message...这样我们就能验证客户端到服务器的链路是否通畅。4.2 使用编辑器进行联机预测试在打包服务器端之前先在编辑器里做一次联机预测试能节省大量时间。操作步骤如下在编辑器工具栏中点击 Play 旁边的小箭头。选择Number of Players为 2。勾选Run Dedicated Server。点击 Play。此时编辑器会启动一个额外的 DS 进程。打开Window-Developer Tools-Output Log可以看到服务端进程的日志输出包括[SERVER] Player joined之类的信息。预测试的目的确认 GameMode / PlayerController 配置正确。确认 RPC 调用链路正常。确认日志输出内容符合预期。如果这时日志没有出现在 Output Log 中先不要急着打包回到上一节检查路径和类名配置。4.3 打包专用服务器的完整命令预测试通过后开始正式打包。UE 提供了批量打包工具RunUAT.bat位置在引擎目录的Engine\Build\BatchFiles\RunUAT.bat。一个常见的 Windows 专用服务器打包命令如下UE安装路径\Engine\Build\BatchFiles\RunUAT.bat BuildCookRun ^ -projectD:\Projects\MyProject\MyProject.uproject ^ -platformWin64 ^ -clientconfigDevelopment ^ -serverconfigDevelopment ^ -cook -stage -pak -archive ^ -archivedirectoryD:\BuildOutput\DS_Win64 ^ -server -noclient参数含义-project项目 uproject 文件路径。-platformWin64目标平台Windows 专用服务器一般用 Win64如果要部署到 Linux 云服务器改-platformLinux。-clientconfigDevelopment和-serverconfigDevelopment开发阶段使用 Development方便查看日志正式发布可换成 Shipping体积更小、性能更高但日志和调试符号会少。-cook执行 Cook 资源。-stage把产物暂存到输出目录。-pak打包成 Pak 文件减少散文件数量。-archive归档到-archivedirectory指定的目录。-server -noclient只打包服务器端不生成客户端。执行成功后D:\BuildOutput\DS_Win64目录下会出现一个类似MyProjectServer.exe的可执行文件以及MyProject目录、Engine目录等依赖文件。4.4 打包 Linux 服务器端如果准备部署到 Linux 云服务器需要先在 UE 中安装 Linux 交叉编译工具链。打开编辑器的Tools-Platforms-Linux点击SetupUE 会自动检查并提示安装。安装完成后需要确保 Linux 工具链指向正确。一般 Windows 在安装 Visual Studio 时勾选了 Linux 开发组件或者跟随 UE 的提示安装clang、lld等工具。打包命令如下UE安装路径\Engine\Build\BatchFiles\RunUAT.bat BuildCookRun ^ -projectD:\Projects\MyProject\MyProject.uproject ^ -platformLinux ^ -clientconfigDevelopment ^ -serverconfigDevelopment ^ -cook -stage -pak -archive ^ -archivedirectoryD:\BuildOutput\DS_Linux ^ -server -noclient注意-platformLinux的作用是对 Cook 和编译目标平台同时生效。打包出的 Linux 专用服务器通常是一个不带扩展名的二进制文件MyProjectServer以及一系列.so动态库和资源目录。4.5 部署到局域网 Windows 主机打包成功后最简单的部署方式是在同一局域网内找一台 Windows 机器把D:\BuildOutput\DS_Win64整个目录拷贝过去。打开命令行进入服务器目录执行MyProjectServer.exe MyProject -log -port7777参数说明MyProject启动的第一个 Map 或项目名。通常填入项目名DS 会根据ServerDefaultMap配置自动进入默认地图。-log启用日志输出同时把日志写入Saved\Logs\MyProject.log。-port7777监听端口可根据需要修改。如果服务器启动正常终端会持续输出网络日志同时会出现[SERVER] Player joined这样的消息。4.6 部署到 Linux 云服务器Linux 云服务器上操作略有不同。先把DS_Linux目录上传到服务器例如/home/ubuntu/MyServer。然后给二进制文件添加执行权限并启动chmod x MyProjectServer ./MyProjectServer MyProject -log -port7777 为了让服务端在后台稳定运行不建议直接使用挂后台推荐使用screen或tmuxscreen -S ue5server ./MyProjectServer MyProject -log -port7777按CtrlA再按D可以分离 screen 会话服务器继续运行。如果服务器不能直接运行先检查系统库ldd MyProjectServer | grep not found缺少依赖时需要手动安装对应的运行库。常见的缺失库包括libssl.so、libicu等。4.7 云服务器安全组与防火墙配置云服务器需要放行 UDP 7777 端口如果通过 HTTP 查询端口或其它服务也需要对应放行。以常见云平台为例在安全组规则中添加入方向 UDP 端口 7777来源建议先限制为固定 IP测试通过后再按需放开。Windows 专用服务器还可能被系统防火墙拦截需要在控制台里放行MyProjectServer.exe或者临时用管理员 PowerShell 执行New-NetFirewallRule -DisplayName UE5 DS UDP 7777 -Direction Inbound -Protocol UDP -LocalPort 7777 -Action Allow注意云服务器和家用宽带还涉及公网 IP、路由器端口映射等问题。如果服务器本身没有独立公网 IP需要在家用路由器上做 UDP 端口转发如果只是局域网测试则可以跳过这一步。5. 连接服务器并打印调试信息5.1 客户端启动与连接方式客户端连接服务器有两种常见方式。方式一使用控制台命令先正常启动打包后的客户端需要有渲染的客户端包按~键打开控制台输入open 192.168.1.100:7777其中192.168.1.100换成服务器 IP7777换成服务器监听端口。方式二启动时直接加命令行参数修改客户端快捷方式在目标后面追加 IP 和端口MyProject.exe 192.168.1.100:7777 -log这种方式适合自动化测试脚本。5.2 客户端打印本地调试信息为了在客户端屏幕上看到日志可以在MyPlayerController::BeginPlay中加入if (IsLocalController()) { GEngine-AddOnScreenDebugMessage( -1, 10.0f, FColor::Green, FString::Printf(TEXT([CLIENT] Connected to server, ControllerName%s), *GetName()) ); }这样客户端连上服务器后屏幕左上角会显示绿色文字提示控制器已生成。5.3 服务器端日志文件位置Dedicated Server 启动后日志默认写在项目的Saved\Logs\目录下。Windows 上通常是MyProjectServer\Saved\Logs\MyProject.logLinux 上则取决于启动时的工作目录一般也在Saved\Logs\目录下。查看实时日志可以用tail -f Saved/Logs/MyProject.log5.4 在日志中显示网络状态UE 控制台内置了很多网络调试指令。在服务器终端里输入stat net可以看到网络复制带宽、Actor 复制数量等信息。在客户端控制台输入netconnection或open 192.168.1.100:7777之后输入stat net可以看到客户端到服务器的连接信息。5.5 自动化日志输出方案如果需要把 UE_LOG 同时输出到控制台和文件并且按日期/大小轮转建议在项目配置中启用日志自动归档。UE 的日志系统默认支持启动参数MyProjectServer.exe MyProject -log -LogCmdsLogTemp Verbose, LogMyProject Verbose其中-LogCmds可以调整日志分类的输出级别。LogTemp Verbose表示把 LogTemp 分类输出级别设为 Verbose打印更多细节。多个日志分类用逗号分隔。生产环境还可以配合-AbsLog...指定日志绝对路径避免工作目录变化导致日志分散MyProjectServer.exe MyProject -log -AbsLog/var/log/ue5/MyProject.log5.6 完整运行验证流程建议按下面的流程完整验证一遍启动专用服务器确认终端出现LogNet相关监听日志。在另一台机器或同一台机器启动客户端用open 服务器IP:7777连接。检查服务器终端出现[SERVER] Player joined: PlayerController_0。检查客户端屏幕出现[CLIENT] Connected to server绿色文本。在客户端调用 RPC 发送自定义消息检查服务器端是否打印[SERVER] Received message。如果每一步都成立说明从打包到部署再到日志输出的整个链路是通的。6. 常见问题与排查思路6.1 客户端连接不上服务器问题现象常见原因解决思路open 命令后一直连接超时服务器未启动或端口不正确确认服务器端进程存在netstat 检查端口监听云服务器公网 IP 连不上安全组未放行 UDP 7777添加安全组规则放行对应协议端口局域网内能连公网不能连路由器未做端口映射在路由器上配置 UDP 端口映射客户端和服务器版本不一致Cook 资源或引擎版本不同使用同一引擎版本重新打包客户端和服务端客户端一直卡在 Loading地图路径配置错误检查 ServerDefaultMap 和对应地图是否被 Cook最常用的排查命令是netstat -ano | findstr 7777如果能看到UDP 0.0.0.0:7777说明服务器正在监听。如果没有检查启动参数和日志输出。6.2 服务器启动后立即崩溃专用服务器启动后闪退常见原因是ServerDefaultMap配置的路径不存在或地图资源未 Cook。某个插件不支持服务器端启动时加载失败。显卡相关初始化代码在 DS 上崩溃。排查步骤用-log启动查看启动完整日志崩溃原因通常会在日志末尾给出。在编辑器中启用Run Dedicated Server预测试确认项目本身支持 DS。检查Saved\Logs\MyProject.log最后的异常堆栈。6.3 输出日志看不到自定义信息如果客户端或服务器端没有打印[SERVER]/[CLIENT]日志优先检查是否真正使用了自定义 GameMode / PlayerController而不是默认类。是否在项目设置里把自定义类配置为默认。日志级别是否被过滤例如LogTemp级别过高时 Warning 会显示Log 可能被忽略。客户端和服务器端是否读取了同一个DefaultEngine.ini配置。6.4 RPC 调用没有触发RPC 没有触发是很常见的联机问题。原因通常是客户端调用的对象没有服务器端 Authority。RPC 被 Unreal 的网络系统判定为无效调用。服务器端和客户端蓝图/类不匹配。没有正确标记Replicated或Server关键字。排查办法在调用前打印本机角色UE_LOG(LogTemp, Warning, TEXT(HasAuthority%d LocalRole%d RemoteRole%d), HasAuthority(), (int32)GetLocalRole(), (int32)GetRemoteRole());确认 RPC 函数名以Server开头这是 UE 的硬性约定。确认WithValidation时_Validate返回 true。6.5 Windows 资源保护或文件占用问题打包过程偶尔会遇到系统级文件占用例如杀毒软件锁定了打包目录导致写入失败。如果出现类似“文件被占用”“访问被拒绝”的报错检查是否在运行打包工具时启动了游戏进程。杀毒软件是否隔离了打包产物。输出目录是否被其他进程打开例如资源管理器正在浏览该目录。6.6 服务器日志文件不刷新如果使用tail -f查看 Linux 日志发现长时间不更新首先确认服务器进程没有崩溃其次确认日志写入路径是否正确。可以用-AbsLog指定固定路径./MyProjectServer MyProject -log -AbsLog/tmp/MyProject.log7. 最佳实践与工程建议7.1 区分服务器逻辑与客户端逻辑开发联机功能时要形成条件反射能在服务器端计算的逻辑绝不放客户端。例如伤害判定、得分、掉落物品生成都应该由服务器作为权威。客户端的职责是发送输入请求和表现。代码中经常用到的判断if (HasAuthority()) { // 服务器逻辑 } else { // 客户端逻辑 }对于只应在客户端运行的逻辑比如 UI 显示、特效播放推荐用IsLocalController()或IsLocallyControlled()判断。7.2 日志规范联机调试时日志一定要带上下文信息下面是一个推荐的日志格式UE_LOG(LogMyProject, Warning, TEXT([%s] GameMode PostLogin, PlayerName%s), HasAuthority() ? TEXT(SERVER) : TEXT(CLIENT), *GetName());这样日志文件名和代码位置都能被快速定位。正式项目还可以使用自定义FLogCategory把不同模块的日志分类管理。7.3 安全加固一旦服务器部署到公网就会面临恶意攻击风险。要注意所有客户端 RPC 都要加WithValidation校验参数合法性并且限制频率。不暴露不必要的端口只开放 UDP 7777 等必须端口。使用独立的服务器账户运行 DS不要使用 root 或管理员权限。定期更新引擎版本及时修复官方公布的安全漏洞。如果涉及玩家数据存档使用 HTTPS 或带签名的请求访问数据库不要把数据库端口暴露到公网。7.4 自动化打包与部署手动打包在项目初期没问题但到了迭代阶段会非常耗时。建议把打包命令写成脚本放到 CI 工具中执行。Windows 端打包脚本build_server.batecho off set UE5UE安装路径\Engine\Build\BatchFiles\RunUAT.bat set PROJECTD:\Projects\MyProject\MyProject.uproject set OUTPUTD:\BuildOutput\DS_Win64 call %UE5% BuildCookRun -project%PROJECT% -platformWin64 -clientconfigDevelopment -serverconfigDevelopment -cook -stage -pak -archive -archivedirectory%OUTPUT% -server -noclient echo Build finished. pauseLinux 部署脚本可以配合rsync或scp上传产物rsync -avz --delete ./DS_Linux/ ubuntu服务器IP:/home/ubuntu/MyServer/7.5 容器化部署如果服务器环境比较多可以考虑用 Docker 打包 UE 专用服务器。官方没有提供 UE 编译镜像但可以在容器里安装引擎依赖后直接运行打包产物。一个最小的Dockerfile示例FROM ubuntu:22.04 RUN apt-get update apt-get install -y \ libssl3 \ libicu70 \ libxss1 \ libasound2 \ libcurl4 \ libpulse0 \ rm -rf /var/lib/apt/lists/* WORKDIR /server COPY . /server EXPOSE 7777/udp CMD [./MyProjectServer, MyProject, -log, -port7777]构建和启动docker build -t ue5-ds:latest . docker run -d --name ue5-ds -p 7777:7777/udp ue5-ds:latest这里要特别提醒Docker 镜像体积会很大因为 UE 打包产物包含大量引擎文件。建议保留基础镜像复用层减少重复上传。7.6 性能与资源限制专用服务器虽然是独立进程但不代表没有性能压力。实测中发现第三人称模板空场景在 2 核 4GB 云服务器上能稳定支撑个位数玩家但如果引入大量物理模拟、AI、高频 RPC性能会快速下降。优化建议控制NetServerMaxTickRate不是越高越好。减少高频复制属性优先使用ReplicatedUsing事件驱动同步。大量客户端可见的 Actor 使用NetUpdateFrequency降频。服务器端关闭不必要的物理模拟比如装饰物破碎效果。7.7 版本管理和多人协作联机项目往往涉及多人在同一个地图上协作开发建议使用 Git 或 Perforce忽略Intermediate、Saved、Binaries目录。提交.uproject和Source目录中的所有配置。大型二进制资源使用 Git LFS 或专用资产管理服务。每次服务端协议变更通知所有客户端更新版本尽量保持协议兼容。8. 总结与后续学习路线到这里虚幻引擎 5.8 联机打包部署的核心流程已经完整走通我们理解了 Listen Server 与 Dedicated Server 的区别配置了自定义 GameMode 和 PlayerController了解了 UE_LOG 与 RPC 的基本机制使用 RunUAT 命令打包了 Windows/Linux 专用服务器完成了局域网和云服务器的部署最后用客户端连接服务器并打印出了完整的调试信息。接下来你可以继续深入的方向包括熟悉属性复制Replication和 RPC 的完整机制实现角色移动同步、攻击判定等真实游戏逻辑。学习 Online Subsystem接入 Steam 或 EOS 联机大厅。学习会话管理Sessions和匹配机制实现房间列表和快速匹配。引入 CI/CD 流水线让服务端打包、测试、部署一键完成。研究服务器存档系统把玩家数据写入数据库。在实际项目中优先关注的问题仍然是安全、性能和日志可观测性。先保证服务器进程能稳定跑起来再逐步叠加玩法逻辑。如果你按本文流程操作遇到了新的报错欢迎在评论区带上你的服务器日志和启动命令一起交流。