본문 바로가기

Unreal

UE4 C++ WebSocket 과 Event 사용하기

웹소켓을 사용하려면 Build.cs 파일에 "WebSockets"을 추가해 주어야 합니다.

using UnrealBuildTool;

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

		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
	}
}

 

헤더파일에는 아래의 헤더파일을 include 해주어야 합니다.

#include <Runtime/Online/WebSockets/Public/WebSocketsModule.h>
#include <Runtime/Online/WebSockets/Public/IWebSocket.h>

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include <Runtime/Online/WebSockets/Public/WebSocketsModule.h>
#include <Runtime/Online/WebSockets/Public/IWebSocket.h>
#include "MyWebSocket.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDele_Dynamic_OneParam, const FString&, Msg);

UCLASS()
class SOCKETIO_TEST_API AMyWebSocket : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AMyWebSocket();
	TSharedPtr<IWebSocket> Socket;

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	//virtual void Tick(float DeltaTime) override;
	
	UFUNCTION(BlueprintCallable, Category = "MyWebSocket")
	void ConnectServer(FString serverURL, FString serverProtocol);
	UFUNCTION(BlueprintCallable, Category = "MyWebSocket")
	void SendString(FString msg);
	UFUNCTION(BlueprintCallable, Category = "MyWebSocket")
	void DisconnectServer();
	UFUNCTION(BlueprintNativeEvent)
	void OnConnected();
	virtual void OnConnected_Implementation();

	// 블루프린트 네이티브 이벤트 처리방식
	UFUNCTION(BlueprintNativeEvent)
	void OnReceived(const FString& param);
	virtual FString OnReceived_Implementation(FString param);

	// 다이나믹 델리게이트 이벤트 처리방식
	UPROPERTY(BlueprintAssignable, VisibleAnywhere, BlueprintCallable, Category = "Event")
	FDele_Dynamic_OneParam OnMsgReceived;

};

 

메세지 처리 같은 부분에 블루프린트에서 이벤트를 사용하고 싶다면, 2가지 방식이 있습니다.

1. DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDele_Dynamic_OneParam, const FString&, Msg);

UCLASS()
class SOCKETIO_TEST_API AMyWebSocket : public AActor
{
	GENERATED_BODY()
    
    // 다이나믹 델리게이트 이벤트 처리방식
	UPROPERTY(BlueprintAssignable, VisibleAnywhere, BlueprintCallable, Category = "Event")
	FDele_Dynamic_OneParam OnMsgReceived;
};

2. UFUNCTION(BlueprintNativeEvent)

// 블루프린트 네이티브 이벤트 처리방식
	UFUNCTION(BlueprintNativeEvent)
	void OnReceived(const FString& param);
	virtual FString OnReceived_Implementation(FString param);

 

 

cpp 파일에서 웹소켓 기능을 구현해 줍니다.

#include "MyWebSocket.h"

// Sets default values
AMyWebSocket::AMyWebSocket()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = false;

}

// Called when the game starts or when spawned
void AMyWebSocket::BeginPlay()
{
	Super::BeginPlay();
}



void AMyWebSocket::ConnectServer(FString serverURL, FString serverProtocol)
{
	
	//FWebSocketsModule& Module = FModuleManager::LoadModuleChecked<FWebSocketsModule>(TEXT("WebSockets"));

	//const FString ServerURL = TEXT("ws://127.0.0.1:3000/"); // Your server URL. You can use ws, wss or wss+insecure.
	//const FString ServerProtocol = TEXT("ws");              // The WebServer protocol you want to use.

	const FString ServerURL = serverURL;
	const FString ServerProtocol = serverProtocol;

	Socket = FWebSocketsModule::Get().CreateWebSocket(ServerURL, ServerProtocol);

	// We bind all available events
	Socket->OnConnected().AddLambda([this]() {
		UE_LOG(LogTemp, Log, TEXT("Connected to websocket server."));
		Socket->Send("{\"event\": \"test\", \"data\": \"test message data\"}");
		OnConnected();
	});

	Socket->OnConnectionError().AddLambda([](const FString & Error) -> void {
		// This code will run if the connection failed. Check Error to see what happened.
	});

	Socket->OnClosed().AddLambda([](int32 StatusCode, const FString& Reason, bool bWasClean) -> void {
		// This code will run when the connection to the server has been terminated.
		// Because of an error or a call to Socket->Close().
	});

	Socket->OnMessage().AddLambda([this](const FString & Message) -> void {
		// This code will run when we receive a string message from the server.
		UE_LOG(LogTemp, Log, TEXT("Received message from websocket server: \"%s\"."), *Message);
		OnReceived(Message);
		OnMsgReceived.Broadcast(Message);
	});

	Socket->OnRawMessage().AddLambda([](const void* Data, SIZE_T Size, SIZE_T BytesRemaining) -> void {
		// This code will run when we receive a raw (binary) message from the server.
	});

	Socket->OnMessageSent().AddLambda([](const FString& MessageString) -> void {
		// This code is called after we sent a message to the server.
	});

	// And we finally connect to the server. 
	Socket->Connect();
}

void AMyWebSocket::OnConnected_Implementation()
{

}

FString AMyWebSocket::OnReceived_Implementation(FString param)
{
	return param;
}

void AMyWebSocket::SendString(FString msg)
{
	if (!Socket->IsConnected())
	{
		// Don't send if we're not connected.
		return;
	}

	//const FString StringMessage = TEXT("Hello there !");
	//const TArray BinaryMessage = { 'H', 'e', 'l', 'l', 'o', ' ', 't', 'h', 'e', 'r', 'e', ' ', '!' };

	Socket->Send(msg);
	//Socket->Send(BinaryMessage.GetData(), sizeof(uint8) * BinaryMessage.Num());
}

void AMyWebSocket::DisconnectServer()
{
	if (!Socket->IsConnected())
	{
		// Don't send if we're not connected.
		return;
	}

	Socket->Close();
}