第十二篇:Unity与UE4的通信机制(二):UE4与UE4通信

接着今天给大家介绍一下UE4与UE4之间的通信。
这里使用的是TCP的通信方式。
首先是服务器端,新建一个工程,然后新建一个C++类,然后就会产生两个文件:.cpp文件和.h文件
.cpp文件代码

   #include "TCPServe.h"
#include "TCPSocketServer.h"


// Sets default values
ATCPSocketServer::ATCPSocketServer()
{
	//初始化
	PrimaryActorTick.bCanEverTick = true;

	SocketServer = NULL;
	SocketClient = NULL;
}

void ATCPSocketServer::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	Super::EndPlay(EndPlayReason);
	if (SocketServer)
	{
		//关闭,销毁
		SocketServer->Close();
		ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(SocketServer);
	}
	if (SocketClient)
	{
		//关闭,销毁
		SocketClient->Close();
		ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(SocketClient);
	}
}

bool ATCPSocketServer::createSoc()
{
	SocketServer = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateSocket(NAME_Stream, TEXT("default"), false);

	if (!SocketServer) {
		return false;
	}
	// SocketServer.SetNonBlocking(false);
	//SocketServer->SetNonBlocking(false);
	return true;
}

bool ATCPSocketServer::bindSoc(const FString & TheIP, const int32 ThePort)
{
	FIPv4Address::Parse(TheIP, ip);
	TSharedRef<FInternetAddr> addr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
	addr->SetIp(ip.Value);
	addr->SetPort(ThePort);
	bool bBind = SocketServer->Bind(*addr);
	return bBind;
}

bool ATCPSocketServer::listenSoc(const int32 MaxBacklog)
{
	bool bListen = SocketServer->Listen(MaxBacklog);
	return bListen;
}

bool ATCPSocketServer::acceptSoc(const FString & TheIP, const int32 ThePort)
{
	TSharedRef<FInternetAddr> targetAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
	FIPv4Address::Parse(TheIP, ip);
	targetAddr->SetIp(ip.Value);
	targetAddr->SetPort(ThePort);
	SocketClient = SocketServer->Accept(*targetAddr, "aaa");
	if (!SocketClient)
		return false;
	return true;
}

bool ATCPSocketServer::sendSoc(const FString & sendMessage)
{
	TSharedRef<FInternetAddr> targetAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
	//FIPv4Address::Parse(TheIP, ip);
	//targetAddr->SetIp(ip.Value);
	//targetAddr->SetPort(ThePort);

	FString serialized = sendMessage;

	bool bsend;
	TCHAR *seriallizedChar = serialized.GetCharArray().GetData();
	int32 size = FCString::Strlen(seriallizedChar) + 1;
	int32 sent = 0;
	//注意,要用客户端这个socket
	bsend = SocketClient->SendTo((uint8*)TCHAR_TO_UTF8(seriallizedChar), size, sent, *targetAddr);

	if (bsend)
	{
		GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, TEXT("_____Send Succ!"));
		UE_LOG(LogTemp, Warning, TEXT("_____Send Succ!"));
	}
	else
	{
		GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, TEXT("_____Send failed!"));
		UE_LOG(LogTemp, Warning, TEXT("_____Send failed!"));
	}
	return bsend;
}

int ATCPSocketServer::recvSoc()
{
	TSharedRef<FInternetAddr> targetAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
	TArray<uint8> ReceivedData;//定义一个接收器
	uint32 Size;
	int32 clientNum;

	if (SocketClient->HasPendingData(Size))
	{
		uint8 *Recv = new uint8[Size];
		int32 BytesRead = 0;
		//将数组调整到给定数量的元素。 新元素将被初始化。
		ReceivedData.SetNumUninitialized(FMath::Min(Size, 65507u));
		//注意,要用客户端这个socket
		SocketClient->RecvFrom(ReceivedData.GetData(), ReceivedData.Num(), BytesRead, *targetAddr);
		if (ReceivedData.Num() > 0)
		{
			//打印
			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Data Bytes Read ~> %d"), ReceivedData.Num()));
			FString ReceivedUE4String = StringFromBinaryArray(ReceivedData);
			GEngine->AddOnScreenDebugMessage(-1, 0.5f, FColor::Red, FString::Printf(TEXT("As String Data ~> %s"), *ReceivedUE4String));
			clientNum = ReceivedData.Num() - 1;
			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("AAAAAAAAAAAA ~> %d"), clientNum));

			//判断是否发送了相对的指令,进行对应事件调用
			if (ReceivedUE4String.Equals("1"))
			{
				sendSoc("server auto send ");
			}
		}
	}
	/*GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Data Bytes Read ~> %d"), clientNum));

	return clientNum;*/
	//clientNum = ReceivedData.Num() - 1;

	return clientNum;

}

FString ATCPSocketServer::StringFromBinaryArray(const TArray<uint8>& BinaryArray)
{
	return FString(ANSI_TO_TCHAR(reinterpret_cast<const char*>(BinaryArray.GetData())));
}

.h文件代码

   #pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Networking.h"
#include "TCPSocketServer.generated.h"

UCLASS()
class TCPSERVE_API ATCPSocketServer : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ATCPSocketServer();

public:
	/** Called whenever this actor is being removed from a level */
	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

	UFUNCTION(BlueprintCallable, Category = "ServerTemp")
		bool createSoc();
	UFUNCTION(BlueprintCallable, Category = "ServerTemp")
		bool bindSoc(const FString& TheIP, const int32 ThePort);
	UFUNCTION(BlueprintCallable, Category = "ServerTemp")
		bool listenSoc(const int32 MaxBacklog);
	UFUNCTION(BlueprintCallable, Category = "ServerTemp")
		bool acceptSoc(const FString& TheIP, const int32 ThePort);
	UFUNCTION(BlueprintCallable, Category = "ServerTemp")
		bool sendSoc(const FString& sendMessage);
	UFUNCTION(BlueprintCallable, Category = "ServerTemp")
		int recvSoc();
	FString StringFromBinaryArray(const TArray<uint8>& BinaryArray);
	FSocket* SocketServer;
	FSocket* SocketClient;
	FIPv4Address ip;
	
	
};

还有一个工程的.Build.cs的文件需要修改

using UnrealBuildTool;

public class SOCKETNOW : ModuleRules
{
	public SOCKETNOW(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
	
		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore","Networking","Sockets" });

		PrivateDependencyModuleNames.AddRange(new string[] {  });

		// Uncomment if you are using Slate UI
		// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
		
		// Uncomment if you are using online features
		// PrivateDependencyModuleNames.Add("OnlineSubsystem");

		// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
	}
}

回到引擎,点击编译,编译完成后,新建一个蓝图类继承刚才新建的C++类,打开蓝图类
在这里插入图片描述
在这里插入图片描述
客户端重新新建一个工程,同样的新建一个C++类,生成.cpp文件和.h文件。
.cpp文件代码

#include "SOCKETNOW.h"
#include "SOCKET.h"


// Sets default values
ASOCKET::ASOCKET()
{
 	// 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;
	SocketClient = NULL;
}

// Called when the game starts or when spawned
void ASOCKET::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	Super::EndPlay(EndPlayReason);
	if (SocketClient)
	{
		//关闭,销毁
		SocketClient->Close();
		ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(SocketClient);
	}
}

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

}
bool ASOCKET::SocketCreate(FString IPStr, int32 port)
{
	FIPv4Address::Parse(IPStr, ip);

	TSharedRef<FInternetAddr> addr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
	addr->SetIp(ip.Value);
	addr->SetPort(port);

	SocketClient = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateSocket(NAME_Stream, TEXT("default"), false);

	if (SocketClient->Connect(*addr))
	{
		GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, TEXT("Connect Succ!"));
		UE_LOG(LogTemp, Warning, TEXT("Connect Succ!"));
		return true;
	}
	else
	{
		GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, TEXT("Connect failed!"));
		UE_LOG(LogTemp, Warning, TEXT("Connect failed!"));
		return false;
	}
}

void ASOCKET::SocketSend(FString meesage)
{
	TCHAR *seriallizedChar = meesage.GetCharArray().GetData();
	int32 size = FCString::Strlen(seriallizedChar) + 1;
	int32 sent = 0;

	if (SocketClient->Send((uint8*)TCHAR_TO_UTF8(seriallizedChar), size, sent))
	{
		GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, TEXT("_____Send Succ!"));
		UE_LOG(LogTemp, Warning, TEXT("_____Send Succ!"));
	}
	else
	{
		GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, TEXT("_____Send failed!"));
		UE_LOG(LogTemp, Warning, TEXT("_____Send failed!"));
	}
}

void ASOCKET::SocketReceive(bool & bReceive, FString & recvMessage)
{
	recvMessage = "";
	bReceive = false;
	if (!SocketClient)
	{
		return;
	}

	TArray<uint8> ReceiveData;
	uint32 size;
	uint8 element = 0;
	while (SocketClient->HasPendingData(size))
	{
		ReceiveData.Init(element, FMath::Min(size, 65507u));

		int32 read = 0;
		SocketClient->Recv(ReceiveData.GetData(), ReceiveData.Num(), read);

	}

	if (ReceiveData.Num() <= 0)
	{
		return;
	}
	FString log = "Total Data read! num: " + FString::FromInt(ReceiveData.Num() <= 0);

	GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, log);
	UE_LOG(LogTemp, Warning, TEXT("Recv log:   %s"), *log);

	const FString ReceivedUE4String = StringFromBinaryArray(ReceiveData);

	log = "Server:" + ReceivedUE4String;
	GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, log);
	UE_LOG(LogTemp, Warning, TEXT("*** %s"), *log);

	recvMessage = ReceivedUE4String;

	bReceive = true;
}
void ASOCKET::DataBaseRecive(int32 clickNum) 
{
	GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Blue, TEXT("___Pangkai"));
	UE_LOG(LogTemp, Warning, TEXT("_____my name is nownow!!"));
}
FString ASOCKET::StringFromBinaryArray(TArray<uint8> BinaryArray)
{
	return FString(ANSI_TO_TCHAR(reinterpret_cast<const char*>(BinaryArray.GetData())));
}

.h文件代码

#pragma once

#include "GameFramework/Actor.h"
#include "Networking.h"
#include "SOCKET.generated.h"

UCLASS()
class SOCKETNOW_API ASOCKET : public AActor
{
	GENERATED_BODY()
public:	
	// Sets default values for this actor's properties
	ASOCKET();

public:
	/** Called whenever this actor is being removed from a level */
	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
public:
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	UFUNCTION(BlueprintCallable, Category = "MySocket")
		bool SocketCreate(FString IPStr, int32 port);

	UFUNCTION(BlueprintCallable, Category = "MySocket")
		void SocketSend(FString meesage);

	UFUNCTION(BlueprintPure, Category = "MySocket")
		void SocketReceive(bool& bReceive, FString& recvMessage);
	UFUNCTION(BlueprintCallable, Category = "MySocket")
		void DataBaseRecive(int32 clickNum);

	FString StringFromBinaryArray(TArray<uint8> BinaryArray);

	FSocket *SocketClient;
	FIPv4Address ip;
	
};

同样的.Build.cs文件个服务器端一样。
新建蓝图类继承C++类,打开蓝图类
在这里插入图片描述

这里还要说一下如何获取本机的ip和端口,Win+R打开运行,输入cmd打开命令控制面板,输入netstat -an就可以获取服务器ip和端口号,选择状态为TIME_WAIT的一组输入就行了。
在这里插入图片描述

记得要把蓝图类拖入到map中,先运行服务器端,在运行客户端,按C键连接。

蓝图中传输值2到服务器端
按C键连接并传值2到服务器端
服务器端已接收到值2
服务器端已接收到值2.

Demo地址:https://download.csdn.net/download/sxx930923/10903665

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值