客户端.h
需要在Build.cs中加入模块:"Networking","Sockets","Json","JsonUtilities"
// 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 propertiesAClientActorClass();protected:// Called when the game starts or when spawnedvirtual void BeginPlay() override;public:// Called every framevirtual 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
// 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 JSONif (FJsonSerializer::Deserialize(Reader, JsonObject)){// 在这里可以使用JsonObject进行其他操作}else{// JSON解析失败的处理UE_LOG(LogTemp, Error, TEXT("Failed to parse JSON from string"));}// 将最终的JSON字符串赋值给输出参数OutString = Utf8String;
}