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

UE5通过C++实现TcpSocket连接

在 Unreal Engine 5 的 C++ 项目中,实现一个具备消息监听、心跳检测和断线重连功能的 TCP 客户端,可以参考以下完整示例。

准备工作

1、模块依赖

YourModule.Build.cs 文件中,添加对 SocketsNetworking 模块的依赖:

PublicDependencyModuleNames.AddRange(new string[] {"Core","CoreUObject","Engine","Sockets","Networking"
});

2、包含头文件

在相关的 .h 文件中,包含必要的头文件:

#include "Networking.h"
#include "Sockets.h"
#include "SocketSubsystem.h"
#include "IPAddress.h"
#include "HAL/Runnable.h"
#include "HAL/RunnableThread.h"
#include "TimerManager.h"

TcpClient.h

#pragma once#include "CoreMinimal.h"
#include "HAL/Runnable.h"
#include "HAL/RunnableThread.h"
#include "Sockets.h"
#include "SocketSubsystem.h"
#include "TimerManager.h"DECLARE_DELEGATE_OneParam(FOnTcpConnected, bool /*bSuccess*/);
DECLARE_DELEGATE_OneParam(FOnTcpMessage, const TArray<uint8>& /*Data*/);
DECLARE_DELEGATE(FOnTcpDisconnected);class FTcpClient : public FRunnable
{
public:FTcpClient(const FString& InIp, int32 InPort, float InHeartbeatInterval = 5.0f);virtual ~FTcpClient();void Start();void StopClient();bool Send(const TArray<uint8>& Data);FOnTcpConnected OnConnected;FOnTcpMessage   OnMessage;FOnTcpDisconnected OnDisconnected;virtual bool Init() override;virtual uint32 Run() override;virtual void Stop() override;virtual void Exit() override;private:bool TryConnect();void SendHeartbeat();void StartHeartbeat();void StopHeartbeat();FString ServerIp;int32   ServerPort;float   HeartbeatInterval;FSocket*       Socket;FRunnableThread* Thread;FThreadSafeBool bRunThread;FThreadSafeBool bConnected;FTimerHandle HeartbeatTimerHandle;
};

TcpClient.cpp

#include "TcpClient.h"
#include "HAL/PlatformProcess.h"
#include "Async/Async.h"
#include "Engine/World.h"
#include "TimerManager.h"FTcpClient::FTcpClient(const FString& InIp, int32 InPort, float InHeartbeatInterval): ServerIp(InIp), ServerPort(InPort), HeartbeatInterval(InHeartbeatInterval), Socket(nullptr), Thread(nullptr), bRunThread(false), bConnected(false)
{
}FTcpClient::~FTcpClient()
{StopClient();
}void FTcpClient::Start()
{if (Thread == nullptr){bRunThread = true;Thread = FRunnableThread::Create(this, TEXT("TcpClientThread"));}
}void FTcpClient::StopClient()
{bRunThread = false;StopHeartbeat();if (Thread){Thread->Kill(true);delete Thread;Thread = nullptr;}if (Socket){Socket->Close();ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(Socket);Socket = nullptr;}
}bool FTcpClient::Init()
{return TryConnect();
}uint32 FTcpClient::Run()
{TArray<uint8> RecvBuffer;RecvBuffer.SetNumUninitialized(1024);while (bRunThread){if (bConnected){int32 BytesRead = 0;if (Socket->Recv(RecvBuffer.GetData(), RecvBuffer.Num(), BytesRead)){if (BytesRead > 0){TArray<uint8> Data;Data.Append(RecvBuffer.GetData(), BytesRead);OnMessage.ExecuteIfBound(Data);}}else{bConnected = false;OnDisconnected.ExecuteIfBound();Socket->Close();ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(Socket);Socket = nullptr;StopHeartbeat();}}else{FPlatformProcess::Sleep(3.0f);if (TryConnect()){bConnected = true;OnConnected.ExecuteIfBound(true);StartHeartbeat();}}}return 0;
}void FTcpClient::Stop()
{bRunThread = false;
}void FTcpClient::Exit()
{
}bool FTcpClient::TryConnect()
{Socket = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateSocket(NAME_Stream, TEXT("TcpClientSocket"), false);Socket->SetNonBlocking(true);TSharedRef<FInternetAddr> Addr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();bool bIsValid;Addr->SetIp(*ServerIp, bIsValid);Addr->SetPort(ServerPort);if (!bIsValid) return false;bool bOk = Socket->Connect(*Addr);if (bOk){bConnected = true;OnConnected.ExecuteIfBound(true);StartHeartbeat();}return bOk;
}bool FTcpClient::Send(const TArray<uint8>& Data)
{if (bConnected && Socket){int32 BytesSent = 0;return Socket->Send(Data.GetData(), Data.Num(), BytesSent);}return false;
}void FTcpClient::SendHeartbeat()
{FString HeartbeatMsg = TEXT("HEARTBEAT");TArray<uint8> Data;Data.Append((uint8*)TCHAR_TO_UTF8(*HeartbeatMsg), HeartbeatMsg.Len());Send(Data);
}void FTcpClient::StartHeartbeat()
{if (GWorld){GWorld->GetTimerManager().SetTimer(HeartbeatTimerHandle, [this](){SendHeartbeat();}, HeartbeatInterval, true);}
}void FTcpClient::StopHeartbeat()
{if (GWorld){GWorld->GetTimerManager().ClearTimer(HeartbeatTimerHandle);}
}

使用示例

在某个 Actor 中使用:

// .h
TUniquePtr<FTcpClient> TcpClient;// .cpp BeginPlay
TcpClient = MakeUnique<FTcpClient>(TEXT("127.0.0.1"), 7777);
TcpClient->OnConnected.BindLambda([](bool bOk){UE_LOG(LogTemp, Log, TEXT("Connected: %s"), bOk ? TEXT("成功") : TEXT("失败"));
});
TcpClient->OnMessage.BindLambda([](const TArray<uint8>& Data){FString Msg(UTF8_TO_TCHAR(Data.GetData()));UE_LOG(LogTemp, Log, TEXT("Received: %s"), *Msg);
});
TcpClient->OnDisconnected.BindLambda([](){UE_LOG(LogTemp, Warning, TEXT("已断线,正在重连…"));
});
TcpClient->Start();// 发送消息
TArray<uint8> Out;
FString ToSend = TEXT("Hello UE5");
Out.Append((uint8*)TCHAR_TO_UTF8(*ToSend), ToSend.Len());
TcpClient->Send(Out);

这样,你就拥有了一个在独立线程中运行、自动重连、带有心跳检测,并通过委托通知主线程的 TCP 客户端类,可以直接嵌入到 UE5 项目中使用。

注意

在 Unreal Engine 中,FSocket::GetConnectionState() 并不是通过底层 TCP 协议实时探测对端是否已关闭连接,而只是返回之前记录的“连接状态”(ESocketConnectionState)。如果服务器在另一端直接关闭(例如进程退出或调用 Close()),而客户端主动调用 Disconnect()、也未在套接字上执行任何 I/O 操作,那么 GetConnectionState() 会继续报告 SCS_Connected。这是因为:

  1. TCP 的连接关闭需要通过 四次挥手(FIN/ACK)握手 完成,若一端不正确地发起或响应 FIN,另一端的状态不会变成 CLOSED。

  2. UE 中的 GetConnectionState() 并不会自动触发 I/O,也不依赖 OS 的 keep-alive 机制,它只反映最初的连接结果。

  3. 要真正探测断线,需要在套接字上执行一次 Recv()(或 Send())才会返回错误或 0 字节读取。

相关文章:

UE5通过C++实现TcpSocket连接

在 Unreal Engine 5 的 C 项目中&#xff0c;实现一个具备消息监听、心跳检测和断线重连功能的 TCP 客户端&#xff0c;可以参考以下完整示例。 准备工作 1、模块依赖 在 YourModule.Build.cs 文件中&#xff0c;添加对 Sockets 和 Networking 模块的依赖&#xff1a; Publ…...

网络状态可以通过hutool.HttpStatus获取

网络状态可以通过hutool.HttpStatus获取 全部都是静态int类型...

Gemini 2.5 推动视频理解进入新时代

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

谈谈各种IO模型

目前的IO模型有5种&#xff1a;BIO&#xff08;阻塞IO&#xff09;、NIO&#xff08;非阻塞IO&#xff09;、IO多路复用、信号驱动IO、异步IO&#xff08;AIO&#xff09; 了解这些模型之前&#xff0c;我们需要先知道IO模型中的几个概念&#xff1a;阻塞&非阻塞、同步&am…...

基于STM32、HAL库的ADAU1701JSTZ音频接口芯片驱动程序设计

一、简介: ADAU1701JSTZ 是 Analog Devices 公司推出的一款高性能、低功耗音频编解码器 (CODEC) 芯片。它专为便携式音频设备设计,集成了麦克风前置放大器、ADC、DAC、耳机放大器等功能模块,支持多种音频接口和采样率,非常适合与 STM32 微控制器配合使用。 主要特性: 24…...

Linux系统管理与编程20:Apache

兰生幽谷&#xff0c;不为莫服而不芳&#xff1b; 君子行义&#xff0c;不为莫知而止休。 做好网络和yum配置&#xff0c;用前面dns规划的www的IP进行。 #!/bin/bash #----------------------------------------------------------- # File Name: myWeb.sh # Version: 1.0 # …...

BFS算法篇——打开智慧之门,BFS算法在拓扑排序中的诗意探索(下)

文章目录 引言一、课程表1.1 题目链接&#xff1a;https://leetcode.cn/problems/course-schedule/description/1.2 题目分析&#xff1a;1.3 思路讲解&#xff1a;1.4 代码实现&#xff1a; 二、课程表||2.1 题目链接&#xff1a;https://leetcode.cn/problems/course-schedul…...

【入门】纸盒的最大体积是多少?

描述 在一张尺寸为 n * n 厘米的正方形硬纸板的四个角上&#xff0c;分别裁剪掉一个 m * m 厘米的小正方形&#xff0c;就可以做成一个无盖纸盒&#xff0c;请问这个无盖纸盒的最大体积是多少&#xff1f; 立方体的体积 v 底面积 * 高&#xff09; 比如&#xff1a; n 5 &am…...

什么是Vim

Vim可是Linux中最强大、最受欢迎的文本编辑器之一&#xff0c;很多程序员、系统管理员都离不开它。要说清楚Vim的各种功能和用法&#xff0c;似乎有点长&#xff0c;但我会尽量用简单通俗的方式&#xff0c;把Vim的核心知识讲清楚&#xff0c;让你能一步一步开始使用它。 一、…...

QT5.14安装以及新建基础项目

进入qt中文网站&#xff1a;Qt | 软件开发全周期的各阶段工具 额&#xff0c;考虑新手可能还是找不到&#xff0c;我就分享一下我下载的的吧 通过网盘分享的文件&#xff1a;qt-opensource-windows-x86-5.14.2.exe 链接:https://pan.baidu.com/s/1yQTRp-b_ISje5B3UWb7Apw?pw…...

Java Spring MVC -01

SpringMVC 是一种基于 的实现 MVC 设计模式的请求驱动类型的轻量级 Web 框架&#xff0c;属于 Spring FrameWork 的后续产品&#xff0c;已经融合在 Spring Web Flow 中。 First:SpringMVC-01-SpringMVC 概述 SpringMVC 是 Spring 框架的一个模块&#xff0c;用于构建 Web 应…...

KV cache 缓存与量化:加速大型语言模型推理的关键技术

引言 在大型语言模型&#xff08;LLM&#xff09;的推理过程中&#xff0c;KV 缓存&#xff08;Key-Value Cache&#xff09; 是一项至关重要的优化技术。自回归生成&#xff08;如逐 token 生成文本&#xff09;的特性决定了模型需要反复利用历史token的注意力计算结果&#…...

视频编解码学习十一之视频原始数据

一、视频未编码前的原始数据是怎样的&#xff1f; 视频在未编码前的原始数据被称为 原始视频数据&#xff08;Raw Video Data&#xff09;&#xff0c;主要是按照帧&#xff08;Frame&#xff09;来组织的图像序列。每一帧本质上就是一张图片&#xff0c;通常采用某种颜色格式…...

[Java实战]Spring Boot 3 整合 Apache Shiro(二十一)

[Java实战]Spring Boot 3 整合 Apache Shiro&#xff08;二十一&#xff09; 引言 在复杂的业务系统中&#xff0c;安全控制&#xff08;认证、授权、加密&#xff09;是核心需求。相比于 Spring Security 的重量级设计&#xff0c;Apache Shiro 凭借其简洁的 API 和灵活的扩…...

Cursor 编辑器 的 高级使用技巧与创意玩法

以下是针对 Cursor 编辑器 的 高级使用技巧与创意玩法 深度解析,涵盖代码生成优化、工作流定制、隐藏功能等层面,助你将 AI 辅助编程效率提升至新高度: 一、代码生成进阶技巧 1. 精准控制生成粒度 行级控制: 在代码行内用 // > 指定生成方向(替代模糊注释)def merge_…...

mysql性能提升方法大汇总

前言 最近在开发自己的小程序的时候&#xff0c;由于业务功能对系统性能的要求很高&#xff0c;系统性能损耗又主要在mysql上&#xff0c;而业务功能的数据表很多&#xff0c;单表数据量也很大&#xff0c;又涉及到很多场景的数据查询&#xff0c;所以我针对mysql调用做了优化…...

C++标准流详解:cin/cout的绑定机制与cerr/clog的缓冲差异

在C中&#xff0c;标准错误流&#xff08;cerr&#xff09;、标准日志流&#xff08;clog&#xff09;与标准输入输出流&#xff08;cin/cout&#xff09;的行为差异主要体现在缓冲机制和绑定关系上。以下是详细解释&#xff0c;并结合cin和cout的关联性进行对比分析&#xff1…...

BlockMesh Ai项目 监控节点部署教程

项目介绍 BlockMesh 是一个创新、开放且安全的网络&#xff0c;允许用户轻松地将多余的带宽货币化。 它为用户提供了被动获利并参与人工智能数据层、在线隐私、开源和区块链行业前沿的绝佳机会。 此教程为Linux系统教程 教程开始 首先到这里注册账号&#xff0c;注册后保存…...

【Bluedroid】蓝牙 HID DEVICE 初始化流程源码解析

本文深入剖析Android蓝牙协议栈中HID设备&#xff08;BT-HD&#xff09;服务的初始化与启用流程&#xff0c;从接口初始化、服务掩码管理、服务请求路由到属性回调通知&#xff0c;完整展现蓝牙HID服务激活的技术路径。通过代码逻辑梳理&#xff0c;揭示服务启用的核心机制&…...

iOS创建Certificate证书、制作p12证书流程

一、创建Certificates 1、第一步得先在苹果电脑上创建一个.certSigningRequest的文件。首先打开钥匙串&#xff0c;使用快捷键【command空格】——输入【钥匙串】回车&#xff08;找不到就搜一下钥匙串访问使用手册&#xff09; 2、然后在苹果电脑的左上角菜单栏选择【钥匙串…...

curl发送数据不为null,但是后端接收到为null

curl -X POST http://localhost:8080/xiaozhi/test --header "Content-Type: application/json" -d "{\"age\":123}"经过检查发现注解导入错误 正确的应该是 import org.springframework.web.bind.annotation.RequestBody;...

blazor与硬件通信实现案例

在网页接入硬件交互通信方案这篇博客中,曾经提到了网页中接入各种硬件操作的方法,即通过Windows Service作为指令的中转,并建立websocket通信连接,进而实现接入硬件的各种操作。这篇博客就以实际的案例来讲解具体怎么实现。 一、建立Windows Service项目 比如我就建立了一…...

Linux下mysql的安装与远程链接

linux安装mysql 01下载依赖&#xff1a; 找到网址/download下&#xff1a; 最下面MySQL Community&#xff08;mysql社区版&#xff09; 选择MySQL Community Server 选择对应的mysql版本 操作系统版本选择 根据操作系统的版本选择具体版本号 下载离线版本 安装包详情 0…...

esp32硬件支持AT指令

步骤1&#xff1a;下载AT固件 从乐鑫官网或Git鑫GitHub仓库&#xff08;https://github.com/espressif/esp-at&#xff09;获取对应ESP32型号的AT固件&#xff08;如ESP32-AT.bin&#xff09;。 步骤2&#xff1a;安装烧录工具 使用 esptool.py&#xff08;命令行工具&#…...

【HT周赛】T3.二维平面 题解(分块:矩形chkmax,求矩形和)

题意 需要维护 n n n \times n nn 平面上的整点&#xff0c;每个点 ( x , y ) (x, y) (x,y) 有权值 V ( x , y ) V(x, y) V(x,y)&#xff0c;初始都为 0 0 0。 同时给定 n n n 次修改操作&#xff0c;每次修改给出 x 1 , x 2 , y 1 , y 2 , v x_1, x_2, y_1, y_2, v x…...

C++中的虚表和虚表指针的原理和示例

一、基本概念 1. 什么是虚函数&#xff08;virtual function&#xff09;&#xff1f; 虚函数是用 virtual 关键字修饰的成员函数&#xff0c;支持运行时多态&#xff08;dynamic polymorphism&#xff09;。通过基类指针或引用调用派生类重写的函数。 class Base { public:…...

qemu热迁移后内存占用突增问题

1.问题描述 虚拟机配置了memoryBackingmemfd的情况下&#xff0c;热迁移虚拟机后&#xff0c;在目的节点 qemu-kvm 进程占用 rss 会突增很多。 如果去掉这个配置没这个现象。 <memoryBacking><source typememfd/> </memoryBacking>2.问题现象 2.1 不配置…...

鸿蒙 Core File Kit(文件基础服务)之简单使用文件

查看常用的沙箱目录 应用沙箱文件访问关系图 应用文件目录结构图 查看常用的沙箱目录 Entry Component struct Index {build() {Button(查看常用的沙箱目录).onClick(_>{let ctx getContext() // UI下只能使用这个方法&#xff0c;不能 this.contextconsole.log(--应用缓存…...

AI 检测原创论文:技术迷思与教育本质的悖论思考

当高校将 AI 写作检测工具作为学术诚信的 "电子判官"&#xff0c;一场由技术理性引发的教育异化正在悄然上演。GPT-4 检测工具将人类创作的论文误判为 AI 生成的概率高达 23%&#xff08;斯坦福大学 2024 年研究数据&#xff09;&#xff0c;这种 "以 AI 制 AI&…...

基于Qt的app开发第七天

写在前面 笔者是大一下计科生&#xff0c;标题这个项目是笔者这个学期的课设&#xff0c;与学长共创&#xff0c;我负责客户端部分&#xff0c;现在已经实现了待办板块的新建、修改。 这个项目目前已经走上正轨了&#xff0c;博主也实现了主要功能的从无到有&#xff…...