当前位置: 首页 > news >正文

UE网络编程完全指南:UDP TCP WebSocket实现详解

前言

在UE项目开发中,最常用的网络通讯协议主要是 UDP、TCP、WebSocket 这三种。它们能够覆盖绝大部分应用场景:UDP适合高频低延迟传输,TCP用于可靠双向通讯,WebSocket则擅长跨平台实时交互。

本文将展示这三种协议在UE中的基础实现方式,帮助你掌握UE网络编程的核心技术。

注: UE原生已提供HTTP的蓝图支持(Send Http Request节点),本文不再赘述。其他协议如MQTT、gRPC等可根据实际需求引入第三方库实现。


一、UDP通讯:高频低延迟场景

1.1 适用场景

  • 传感器数据采集(LiDAR、Camera、GPS)
  • 仿真器对接(CarSim、PreScan)
  • 局域网广播/组播
  • 实时控制指令

1.2 基础实现

创建UDP Socket并绑定端口:

#include "Sockets.h"
#include "SocketSubsystem.h"// 获取Socket子系统
ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);// 创建UDP Socket
FSocket* RecvSocket = SocketSubsystem->CreateSocket(NAME_DGram, TEXT("UDP Receiver"), false);// 创建地址并绑定
TSharedRef<FInternetAddr> Addr = SocketSubsystem->CreateInternetAddr();
Addr->SetPort(8888);
Addr->SetAnyAddress();if (RecvSocket->Bind(*Addr))
{UE_LOG(LogTemp, Log, TEXT("UDP Socket绑定成功,端口: 8888"));
}// 设置非阻塞模式
RecvSocket->SetNonBlocking(true);

接收UDP数据:

void ReceiveUDPData(FSocket* RecvSocket)
{ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);TArray<uint8> RecvData;RecvData.SetNumUninitialized(65507); // UDP最大包大小int32 BytesRead = 0;TSharedRef<FInternetAddr> SenderAddr = SocketSubsystem->CreateInternetAddr();if (RecvSocket->RecvFrom(RecvData.GetData(), RecvData.Num(), BytesRead, *SenderAddr)){RecvData.SetNum(BytesRead);FString SenderIP = SenderAddr->ToString(false);int32 SenderPort = SenderAddr->GetPort();UE_LOG(LogTemp, Log, TEXT("收到来自 %s:%d 的数据,大小: %d"),*SenderIP, SenderPort, BytesRead);// 处理接收到的数据ProcessReceivedData(RecvData);}
}

发送UDP数据:

void SendUDPData(const FString& TargetIP, int32 TargetPort, const TArray<uint8>& Data)
{ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);FSocket* SendSocket = SocketSubsystem->CreateSocket(NAME_DGram, TEXT("UDP Sender"), false);TSharedRef<FInternetAddr> RemoteAddr = SocketSubsystem->CreateInternetAddr();bool bIsValid;RemoteAddr->SetIp(*TargetIP, bIsValid);RemoteAddr->SetPort(TargetPort);if (bIsValid){int32 BytesSent = 0;SendSocket->SendTo(Data.GetData(), Data.Num(), BytesSent, *RemoteAddr);UE_LOG(LogTemp, Log, TEXT("发送 %d 字节到 %s:%d"), BytesSent, *TargetIP, TargetPort);}SendSocket->Close();ISocketSubsystem::Get()->DestroySocket(SendSocket);
}

二、TCP通讯:可靠双向传输

2.1 适用场景

  • 连接外部服务器(Python/C#工具链)
  • 可靠指令传输(不允许丢包)
  • 文件传输、资源下载
  • 需要双向通讯的场景

2.2 TCP Client基础实现

连接服务器:

bool ConnectToTCPServer(const FString& IP, int32 Port)
{ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);// 创建TCP SocketFSocket* ClientSocket = SocketSubsystem->CreateSocket(NAME_Stream, TEXT("TCP Client"), false);// 设置目标地址TSharedRef<FInternetAddr> Addr = SocketSubsystem->CreateInternetAddr();bool bIsValid;Addr->SetIp(*IP, bIsValid);Addr->SetPort(Port);if (!bIsValid){UE_LOG(LogTemp, Error, TEXT("无效的IP地址: %s"), *IP);return false;}// 连接if (ClientSocket->Connect(*Addr)){UE_LOG(LogTemp, Log, TEXT("TCP连接成功: %s:%d"), *IP, Port);return true;}else{UE_LOG(LogTemp, Error, TEXT("TCP连接失败"));return false;}
}

发送和接收数据:

// 发送
bool SendTCPData(FSocket* Socket, const TArray<uint8>& Data)
{int32 BytesSent = 0;return Socket->Send(Data.GetData(), Data.Num(), BytesSent);
}// 接收
bool ReceiveTCPData(FSocket* Socket, TArray<uint8>& OutData)
{uint32 PendingDataSize = 0;if (Socket->HasPendingData(PendingDataSize)){OutData.SetNumUninitialized(PendingDataSize);int32 BytesRead = 0;if (Socket->Recv(OutData.GetData(), OutData.Num(), BytesRead)){OutData.SetNum(BytesRead);return true;}}return false;
}

2.3 TCP Server基础实现

监听端口:

bool StartTCPServer(int32 Port)
{ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);// 创建监听SocketFSocket* ListenSocket = SocketSubsystem->CreateSocket(NAME_Stream, TEXT("TCP Server"), false);// 绑定端口TSharedRef<FInternetAddr> Addr = SocketSubsystem->CreateInternetAddr();Addr->SetPort(Port);Addr->SetAnyAddress();if (!ListenSocket->Bind(*Addr)){UE_LOG(LogTemp, Error, TEXT("绑定端口失败: %d"), Port);return false;}// 开始监听(最大8个待连接队列)if (!ListenSocket->Listen(8)){UE_LOG(LogTemp, Error, TEXT("监听失败"));return false;}UE_LOG(LogTemp, Log, TEXT("TCP服务器启动,端口: %d"), Port);return true;
}

接受客户端连接:

void AcceptClients(FSocket* ListenSocket)
{ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);TSharedRef<FInternetAddr> ClientAddr = SocketSubsystem->CreateInternetAddr();FSocket* ClientSocket = ListenSocket->Accept(*ClientAddr, TEXT("TCP Client"));if (ClientSocket){FString ClientIP = ClientAddr->ToString(false);int32 ClientPort = ClientAddr->GetPort();UE_LOG(LogTemp, Log, TEXT("客户端连接: %s:%d"), *ClientIP, ClientPort);// 存储客户端Socket用于后续通讯}
}

三、WebSocket:现代化跨平台通讯

3.1 适用场景

  • Web前端控制面板
  • 云服务实时推送
  • 与浏览器/移动端通讯
  • 需要跨语言、跨平台的统一协议

3.2 UE内置WebSocket模块

UE提供了WebSockets模块,需要在.Build.cs中添加:

PublicDependencyModuleNames.AddRange(new string[] {"Core","WebSockets","Http"
});

3.3 基础实现

连接WebSocket:

#include "IWebSocket.h"
#include "WebSocketsModule.h"void ConnectWebSocket(const FString& URL)
{// 创建WebSocket实例TSharedPtr<IWebSocket> WebSocket = FWebSocketsModule::Get().CreateWebSocket(URL);// 绑定连接成功事件WebSocket->OnConnected().AddLambda([](){UE_LOG(LogTemp, Log, TEXT("WebSocket连接成功"));});// 绑定消息接收事件WebSocket->OnMessage().AddLambda([](const FString& Message){UE_LOG(LogTemp, Log, TEXT("收到消息: %s"), *Message);});// 绑定连接关闭事件WebSocket->OnClosed().AddLambda([](int32 StatusCode, const FString& Reason, bool bWasClean){UE_LOG(LogTemp, Warning, TEXT("WebSocket关闭: %s"), *Reason);});// 发起连接WebSocket->Connect();
}

发送消息:

void SendWebSocketMessage(TSharedPtr<IWebSocket> WebSocket, const FString& Message)
{if (WebSocket.IsValid() && WebSocket->IsConnected()){WebSocket->Send(Message);}
}

注意事项:

  • 打包后使用127.0.0.1而非localhost(避免域名解析问题)
  • UE的WebSocket模块仅支持ws://,不支持wss://加密
  • 连接URL格式: ws://127.0.0.1:8080

四、实际项目中的完善方案

以上代码展示了网络通讯的基础实现,但实际项目中往往需要更完善的功能架构:

  • 多通道管理 — 不同端口处理不同业务逻辑
  • 异步线程处理 — 避免阻塞游戏主线程
  • 自动重连机制 — TCP客户端断线自动重试
  • 会话管理 — TCP服务端区分不同客户端
  • IP过滤 — 白名单/黑名单机制(支持CIDR)
  • 蓝图支持 — 完整的蓝图节点封装
  • 数据序列化 — 结构体与字节数组的双向转换

如果需要开箱即用的完整解决方案,我已经将这些功能封装为以下插件,每个功能独立拆分,方便按需选择:

网络通讯插件

SimpleUDP | Fab — 简单UDP通讯方案

  • 多通道收发管理
  • 异步接收线程
  • IP过滤(白名单/黑名单/CIDR)
  • 广播地址支持
  • 运行时动态配置
  • 完整蓝图接口

SimpleTCPClient | Fab — 简单TCP客户端方案

  • 多通道独立管理
  • 自动重连(可配置间隔)
  • 异步IO处理
  • 连接状态事件委托
  • 蓝图完整支持

SimpleTCPServer | Fab — 简单TCP服务端方案

  • 多客户端会话管理(SessionKey: IP:Port)
  • 为每个客户端独立线程
  • 连接/断开事件通知
  • 运行时通道配置
  • 蓝图完整支持

SimpleWebSocket | Fab — 简单WebSocket方案

  • 命名连接管理
  • 项目启动自动连接
  • 消息委托绑定
  • 完整蓝图封装
  • 打包环境验证

数据处理插件

网络通讯的数据需要序列化为字节数组才能传输,但UE原生功能存在诸多限制:

  • UE的Byte转换节点只能转换为单个Byte,无法转换为Byte数组,会导致数据丢失
  • UE默认的JSON序列化会强制转换字段名为驼峰式,与原始命名不符
  • 浮点数精度不足,序列化后数据失真
  • UE没有提供直接将Struct转换为字节数组的蓝图方法

SimpleByteConversion | Fab — 解决UE原生痛点的数据序列化方案

  • 基础类型双向转换为字节数组(int/float/bool/string/int64/double)
  • 任意结构体的二进制序列化(基于反射,支持复杂嵌套)
  • 结构体JSON序列化(保留原始字段名 + 高精度浮点数)
  • 确保网络传输中数据格式的一致性
  • CustomThunk实现蓝图泛型支持,真正的开箱即用
  • 零依赖,纯UE原生API实现

所有插件均支持UE 5.2+,跨平台兼容,经过多个生产项目验证。


总结

UE网络通讯的核心就是:

  1. 选对协议 — UDP(高频低延迟) / TCP(可靠传输) / WebSocket(跨平台)
  2. 掌握基础 — 理解Socket创建、收发数据的底层逻辑
  3. 完善架构 — 实际项目需要异步处理、多通道管理、蓝图支持等

本文展示了基础实现代码,帮助你理解UE网络通讯的原理。

对于会C++的朋友:
原理讲明白之后,完全可以尝试自己动手实现一套完整的网络通讯方案,这也是很好的学习机会。

对于不会C++的朋友:
可以考虑直接使用我发售在Fab上的插件。价格相对于同类产品来说非常便宜,性价比极高,买一个备用,在以后的职业生涯中大概率能直接用上。

这几个插件其实算是我的练手作品,也成功帮我打通了Fab上架插件的完整流程。虽然功能比较基础,但都经过了实际项目的验证。感兴趣的朋友可以关注一波,后期我还会上架更多实用、性价比高的插件。

如果大家在使用中遇到任何问题,欢迎在评论区留言或通过邮箱联系我,我看到后会积极回应。也请大家多多支持,感谢!

📧 技术交流: mengzhishanghun@outlook.com


本文所有代码均基于UE5.2+实测有效。

http://www.hskmm.com/?act=detail&tid=29141

相关文章:

  • 配置Nginx服务器在Ubuntu平台上
  • 缓存一致性验证秘笈
  • 从十五岁的今天写给十六岁的明天
  • kali U盘启动持久化
  • 深入解析:Telerik UI for ASP.NET MVC 2025 Q3
  • Java依记 DAY02 - I
  • 元推理:汉字的发音,同音也是某种同构?
  • 题解:qoj7759 Permutation Counting 2
  • WAV 转 flac 格式
  • EtherCAT芯片没有倍福授权的风险
  • 为何是「对话式」智能体?因为人类本能丨对话式智能体专场,Convo AIRTE2025
  • 2014-2024高考真题考点分布详细分析(另附完整高考真题下载) - 详解
  • P4147 玉蟾宫(最大子矩形)
  • 2025 年 10 月西安房屋鉴定公司最新推荐排行榜:覆盖房屋安全评估、结构检测、承载力鉴定、危房鉴定领域,助您选专业机构
  • 完整教程:HAProxy 完整指南:简介、负载均衡原理与安装配置
  • K
  • 阿里发布「夸克 AI 眼镜」:融合阿里购物、地图、支付生态;苹果拟收购计算机视觉初创 Prompt AI丨日报
  • 在AI技术唾手可得的时代,挖掘新需求成为制胜关键——某知名AI聊天框架需求探索
  • 数论学习之路
  • 生成式AI实现多模态信息检索技术突破
  • 在运维工作中,如何过滤某个目录在那边什么路径下面?
  • 完整教程:安卓中,kotlin如何写app界面?
  • 移动固态硬盘插入电脑后提示“应该格式化”或“文件系统损坏”如何修复?
  • PHP 15 个高效开发的小技巧
  • AI元人文构想研究:人类拥抱AI的文明新范式
  • 【汇编】汇编语言运行过程
  • 电感式传感器 - 实践
  • CSP-J/S2024第二轮提高级题目知识构成分析报告
  • 浅层 CNN 的瓶颈:用 LeNet 实测不同数据集
  • 文本派 - 停服公告 2025