客户端.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 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 SendData);
UFUNCTION(BlueprintCallable,Category = "TCPServerAndClient")
static bool DisConnectFormClientToServer();
UFUNCTION(BlueprintCallable,Category = "TCPServerAndClient")
static TArray ReceiveDataFromTCPServer();
//"Json","JsonUtilities"
UFUNCTION(BlueprintCallable,Category = "TCPServerAndClient")
static void StringToBytes(FString InString,bool& OutBool,TArray& OutBytesArray);
UFUNCTION(BlueprintCallable,Category = "TCPServerAndClient")
static void DataTypeToJSON(int32 Int,bool Inbool,FString String,FVector Vector,TArray Array,bool& OutBool,TArray& OutBytesArray);
UFUNCTION(BlueprintCallable,Category = "TCPServerAndClient")
static void BytesToString(TArray 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 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 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 AClientActorClass::ReceiveDataFromTCPServer()
{
TArray 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();
}
void AClientActorClass::StringToBytes(FString InString, bool& OutBool, TArray& 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 Array,
bool& OutBool, TArray& OutBytesArray)
{
OutBytesArray.Empty();
TSharedPtr JsonObject = MakeShareable(new FJsonObject);
JsonObject->SetNumberField("MyInteger",Int);
JsonObject->SetBoolField("MyBool",Inbool);
JsonObject->SetStringField("MyString",String);
TSharedPtr VectorObject = MakeShareable(new FJsonObject);
JsonObject->SetNumberField("MyVector",Vector.X);
JsonObject->SetNumberField("MyVector",Vector.Y);
JsonObject->SetNumberField("MyVector",Vector.Z);
JsonObject->SetObjectField("MyVector",VectorObject);
TArray> JsonArray;
for (auto& value : Array)
{
JsonArray.Add(MakeShareable(new FJsonValueNumber(value)));
}
JsonObject->SetArrayField("Array",JsonArray);
// 将 JSON 对象转换为字符串
FString OutputString;
TSharedRef> 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 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(InBytesArray.GetData()), InBytesArray.Num()).Get();
// 在这里你可以使用Utf8String进行其他操作,例如将其转换为JSON对象
// 注意:在UE5中,你可能需要使用FJsonSerializer的Deserialize方法
TSharedPtr JsonObject;
TSharedRef> 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;
}