UE5 C++的TCP服务器与客户端

 客户端.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;
}

你可能感兴趣的:(ue5,c++,tcp/ip)