阅读量:0
客户端.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<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 JSON if (FJsonSerializer::Deserialize(Reader, JsonObject)) { // 在这里可以使用JsonObject进行其他操作 } else { // JSON解析失败的处理 UE_LOG(LogTemp, Error, TEXT("Failed to parse JSON from string")); } // 将最终的JSON字符串赋值给输出参数 OutString = Utf8String; }