UE5 C++的TCP客户端示例

客户端.h

需要在Build.cs中加入模块:"Networking","Sockets","Json","JsonUtilities"

cpp 复制代码
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ClientActorClass.generated.h"

UCLASS()
class TCPSERVERANDCLIENT_API AClientActorClass : public AActor
{
	GENERATED_BODY()

public:
	// Sets default values for this actor's properties
	AClientActorClass();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	static FSocket* Socket;

	//"Networking","Sockets"
	UFUNCTION(BlueprintCallable,Category = "TCPServerAndClient")
	static bool ClientConnectToTCPServer(const FString& IP,int32 Port = 8888);

	UFUNCTION(BlueprintCallable,Category = "TCPServerAndClient")
	static bool SendDataFormClicentToServer(TArray<uint8> SendData);

	UFUNCTION(BlueprintCallable,Category = "TCPServerAndClient")
	static bool DisConnectFormClientToServer();

	UFUNCTION(BlueprintCallable,Category = "TCPServerAndClient")
	static TArray<uint8> ReceiveDataFromTCPServer();

	//"Json","JsonUtilities"
	UFUNCTION(BlueprintCallable,Category = "TCPServerAndClient")
	static void StringToBytes(FString InString,bool& OutBool,TArray<uint8>& OutBytesArray);

	UFUNCTION(BlueprintCallable,Category = "TCPServerAndClient")
	static void DataTypeToJSON(int32 Int,bool Inbool,FString String,FVector Vector,TArray<int32> Array,bool& OutBool,TArray<uint8>& OutBytesArray);

	UFUNCTION(BlueprintCallable,Category = "TCPServerAndClient")
	static void BytesToString(TArray<uint8> InBytesArray,FString& OutString);
};

客户端.cpp

cpp 复制代码
// Fill out your copyright notice in the Description page of Project Settings.


#include "ClientActorClass.h"

#include "Sockets.h"
#include "Internationalization/Text.h"
#include "Misc/OutputDevice.h"
#include "Internationalization/Internationalization.h"
#include "Common/TcpSocketBuilder.h"

FSocket* AClientActorClass::Socket = nullptr;
// Sets default values
AClientActorClass::AClientActorClass()
{
	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
}

// Called when the game starts or when spawned
void AClientActorClass::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void AClientActorClass::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
}

bool AClientActorClass::ClientConnectToTCPServer(const FString& IP, int32 Port)
{
	if (Socket)
	{
		Socket->Close();
		ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(Socket);
		Socket = nullptr;
	}

	TSharedPtr<FInternetAddr> Addr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
	bool bIsValid;
	Addr->SetIp(*IP,bIsValid);
	Addr->SetPort(Port);

	if (!bIsValid)
	{
		UE_LOG(LogTemp,Log,TEXT("InValid IP Address"));
		GEngine->AddOnScreenDebugMessage(-1,5.0f,FColor::Red,TEXT("InValid IP Address"));
		return false;
	}
	Socket = FTcpSocketBuilder(TEXT("TcpClient")).AsBlocking().WithReceiveBufferSize(2*1024*1024);

	bool bConnected = Socket->Connect(*Addr);
	if (!bConnected)
	{
		UE_LOG(LogTemp,Log,TEXT("Failed Connect To Server"));
		GEngine->AddOnScreenDebugMessage(-1,5.0,FColor::Green,TEXT("Failed Connect To Server"));
		return false;
	}
	UE_LOG(LogTemp,Log,TEXT("Success Connect To Server"));
	GEngine->AddOnScreenDebugMessage(-1,5.0,FColor::Green,TEXT("Success Connect To Server"));

	return true;
	
}

bool AClientActorClass::SendDataFormClicentToServer(TArray<uint8> SendData)
{
	if (!Socket)
	{
		UE_LOG(LogTemp, Log, TEXT("Socket is not connected!"));
		return false;
	}

	// 发送数据部分
	int32 SentBytes = 0;
	bool bSuccess = Socket->Send(SendData.GetData(), SendData.Num(), SentBytes);

	if (!bSuccess || SentBytes != SendData.Num())
	{
		UE_LOG(LogTemp, Log, TEXT("Failed to send data!"));
		return false;
	}
	GEngine->AddOnScreenDebugMessage(-1,5.0,FColor::Green,TEXT("Success to send data!"));
	UE_LOG(LogTemp, Log, TEXT("Success to send data!"));
	return true;
}

bool AClientActorClass::DisConnectFormClientToServer()
{
	if (Socket)
	{
		Socket->Close();
		ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(Socket);
		Socket = nullptr;
		return true;
	}
	return false;
}

TArray<uint8> AClientActorClass::ReceiveDataFromTCPServer()
{
	TArray<uint8> Bytes;

	if (Socket)
	{
		uint32 Size;
		while (Socket->HasPendingData(Size))
		{
			Bytes.SetNumUninitialized(FMath::Min(Size, 65507u));

			int32 ReadBytes = 0;
			// 读取数据到字节流中
			Socket->Recv(Bytes.GetData(), Bytes.Num(), ReadBytes);

			// 将实际读取的部分截取出来
			Bytes.SetNum(ReadBytes);

			// 如果需要等待接收完整数据再返回,可以设置一个条件,比如接收到特定结束标志
			// 如果已经接收到完整数据,可以直接返回
			return Bytes;
		}
	}

	// 如果没有接收到数据,返回空字节流
	return TArray<uint8>();
}

void AClientActorClass::StringToBytes(FString InString, bool& OutBool, TArray<uint8>& OutBytesArray)
{
	OutBytesArray.Empty();
	
	if (!InString.IsEmpty())
	{
		FTCHARToUTF8 Converter(*InString);
		int32 NumBytes = Converter.Length();
		if (NumBytes > 0)
		{
			OutBytesArray.Append((uint8*)Converter.Get(), NumBytes);
			OutBool = true;
		}
		else
		{
			OutBool = false;
		}
	}
	else
	{
		OutBool = false;
	}
}

void AClientActorClass::DataTypeToJSON(int32 Int, bool Inbool, FString String, FVector Vector, TArray<int32> Array,
	bool& OutBool, TArray<uint8>& OutBytesArray)
{
	OutBytesArray.Empty();
	
	TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);

	JsonObject->SetNumberField("MyInteger",Int);
	JsonObject->SetBoolField("MyBool",Inbool);
	JsonObject->SetStringField("MyString",String);

	TSharedPtr<FJsonObject> VectorObject = MakeShareable(new FJsonObject);
	JsonObject->SetNumberField("MyVector",Vector.X);
	JsonObject->SetNumberField("MyVector",Vector.Y);
	JsonObject->SetNumberField("MyVector",Vector.Z);

	JsonObject->SetObjectField("MyVector",VectorObject);
	
	TArray<TSharedPtr<FJsonValue>> JsonArray;
	for (auto& value : Array)
	{
		JsonArray.Add(MakeShareable(new FJsonValueNumber(value)));		
	}
	JsonObject->SetArrayField("Array",JsonArray);

	// 将 JSON 对象转换为字符串  
	FString OutputString;
	TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&OutputString);
	if (FJsonSerializer::Serialize(JsonObject.ToSharedRef(), Writer))
	{
		Writer->Close();

		// 将字符串转换为字节数组  
		FTCHARToUTF8 Converter(*OutputString);
		int32 NumBytes = Converter.Length();
		if (NumBytes > 0)
		{
			OutBytesArray.Append((uint8*)Converter.Get(), NumBytes);
			OutBool = true;
		}
		else
		{
			OutBool = false;
		}
	}
	else
	{
		OutBool = false;
	}
}

void AClientActorClass::BytesToString(TArray<uint8> InBytesArray, FString& OutString)
{
	// 检查字节数组是否为空
	if (InBytesArray.Num() == 0)
	{
		OutString.Empty();
		GEngine->AddOnScreenDebugMessage(-1, 2.0, FColor::Blue, TEXT("data = null"));
		UE_LOG(LogTemp, Log, TEXT("data = null"));
		return;
	}

	// 将字节流转换为UTF-8字符串
	FString Utf8String = FUTF8ToTCHAR(reinterpret_cast<const ANSICHAR*>(InBytesArray.GetData()), InBytesArray.Num()).Get();

	// 在这里你可以使用Utf8String进行其他操作,例如将其转换为JSON对象
	// 注意:在UE5中,你可能需要使用FJsonSerializer的Deserialize方法
	TSharedPtr<FJsonObject> JsonObject;
	TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Utf8String);

	// Deserialize JSON
	if (FJsonSerializer::Deserialize(Reader, JsonObject))
	{
		// 在这里可以使用JsonObject进行其他操作
	}
	else
	{
		// JSON解析失败的处理
		UE_LOG(LogTemp, Error, TEXT("Failed to parse JSON from string"));
	}

	// 将最终的JSON字符串赋值给输出参数
	OutString = Utf8String;
}
相关推荐
专注VB编程开发20年2 小时前
除了 EasyXLS,加载和显示.xlsx 格式的excel表格,并支持单元格背景色、边框线颜色和粗细等格式化特性
c++·windows·excel·mfc·xlsx
夏天的阳光吖4 小时前
C++蓝桥杯基础篇(四)
开发语言·c++·蓝桥杯
oioihoii4 小时前
C++17 中的 std::to_chars 和 std::from_chars:高效且安全的字符串转换工具
开发语言·c++
张胤尘4 小时前
C/C++ | 每日一练 (2)
c语言·c++·面试
強云5 小时前
23种设计模式 - 装饰器模式
c++·设计模式·装饰器模式
yatingliu20195 小时前
代码随想录算法训练营第六天| 242.有效的字母异位词 、349. 两个数组的交集、202. 快乐数 、1. 两数之和
c++·算法
我们的五年6 小时前
【Linux网络】TCP/IP地址的有机结合(有能力VS100%???),IP地址的介绍
linux·运维·网络·tcp/ip
鄃鳕6 小时前
单例模式【C++设计模式】
c++·单例模式·设计模式
只做开心事6 小时前
C++之特殊类设计
开发语言·c++
宋康6 小时前
C/C++ 指针避坑20条
c语言·开发语言·c++