Networking/HTTP2018. 12. 20. 20:56

원문 : 언리얼 HTTP 요청 참조

https://wiki.unrealengine.com/UE4.10_How_To_Make_HTTP_GET_Request_in_C%2B%2B


위의 내용을 참조하여 UE4.20에서 테스트해본 내용이며 설명대로 설정하고 코딩한 것을 테스트한 결과 언리얼에서 웹서버에 접속하고 응답을 수신하여 언리얼 화면에 표시할 수 있었다


C++프로젝트 생성

Visual Studio 의 Games/프로젝트이름/Source/프로젝트이름/프로젝트이름.Build.cs 파일을 더블클릭하여 연다


소스코드에서 아래 내용을 찾는다

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });


위의 코드에 HTTP 관련 모듈이름을 추가한다

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore"

,"Http", "Json", "JsonUtilities" });


/Games/프로젝트명/Config/DefaultEngine.ini 파일을 열고 아래의 내용을 추가한다

[HTTP]

HttpTimeout=300

HttpConnectionTimeout=-1

HttpReceiveTimeout=-1

HttpSendTimeout=-1

HttpMaxConnectionsPerServer=16

bEnableHttp=true

bUseNullHttp=false

HttpDelayTime=0



Actor기반의 C++ 클래스를 생성

언리얼 에디터 Content Browser에서 마우스 우측 > C++ 클래스 생성 > Actor > 액터의 이름을 HttpActor 등으로 입력


Visual Studio에 위에서 생성한 클래스의 *.h, *.cpp 파일의 디폴트 코드가 열리면 헤더파일과 소스파일을 다음과 같이 편집한다. 굵게 표시한 코드는 디폴트 코드에 추가된 것이다


헤더파일 편집

// Fill out your copyright notice in the Description page of Project Settings.


#pragma once


#include "CoreMinimal.h"

#include "GameFramework/Actor.h"

#include "Runtime/Online/HTTP/Public/Http.h"

#include "MyHttpActor.generated.h"


UCLASS()

class CPP_HTTP_API AMyHttpActor : public AActor

{

GENERATED_BODY()

public:

FHttpModule* Http;


UFUNCTION()

void MyHttpCall(); // http 요청에 사용할 함수


// http GET 요청 직후 호출되는 콜백함수

void OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);

// 생성자 함수를 약간 변경한다

AMyHttpActor(const class FObjectInitializer& ObjectInitializer);


protected:

// Called when the game starts or when spawned

virtual void BeginPlay() override;


public:

// Called every frame

virtual void Tick(float DeltaTime) override;

};



소스파일 편집

// Fill out your copyright notice in the Description page of Project Settings.


#include "MyHttpActor.h"



// Sets default values

AMyHttpActor::AMyHttpActor(const class FObjectInitializer& ObjectInitializer)

: Super(ObjectInitializer)

{

  // 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;

Http = &FHttpModule::Get();

}


// Called when the game starts or when spawned

void AMyHttpActor::BeginPlay()

{

MyHttpCall();

Super::BeginPlay();

}


void AMyHttpActor::MyHttpCall()

{

TSharedRef<IHttpRequest> Request = Http->CreateRequest();

Request->OnProcessRequestComplete().BindUObject(this, &AMyHttpActor::OnResponseReceived);

//This is the url on which to process the request

Request->SetURL("http://unreal.mywebcommunity.org/getInt.php");

Request->SetVerb("GET");

Request->SetHeader(TEXT("User-Agent"), "X-UnrealEngine-Agent");

Request->SetHeader("Content-Type", TEXT("application/json"));

Request->ProcessRequest();

}


void AMyHttpActor::OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)

{


//Create a pointer to hold the json serialized data

TSharedPtr<FJsonObject> JsonObject;


//Create a reader pointer to read the json data

TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());


//Deserialize the json data given Reader and the actual object to deserialize

if (FJsonSerializer::Deserialize(Reader, JsonObject))

{

//Get the value of the json object by field name

int32 recievedInt = JsonObject->GetIntegerField("customInt");


//Output it to the engine

GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, FString::FromInt(recievedInt));

}

}


// Called every frame

void AMyHttpActor::Tick(float DeltaTime)

{

Super::Tick(DeltaTime);


}



위와 같이 작성된 클래스를 Visual Studio에서 저장하고 언리얼 에디터에서 [컴파일] 버튼을 누른다

컴파일에 성공하면 Content Broswer에서 위의 클래스를 드래그하여 레벨에 배치하면 언리얼 에디터에서 작업은 끝이다


위의 언리얼 프로그램이 접속할 대상은 HTTP 프로토콜을 사용하여 연결되는 웹서버이므로 웹서버에서 위의 접속에 응답할 서버 스크립트가 필요하다. 웹서버에서 실행되는 스크립트는 프로그래밍 언어와 상관없다


getInt.php (위의 언리얼 프로그램에서 접속할 웹서버의 스크립트)

<?php
	//Create a variable to be used in 
	$theVar = array('customInt' => 5);

	//Set the headers
	header('Content-Type: application/json');

	//Encode the variable, and save the encoded string
	$encoded = json_encode($theVar);

	//Output it
	echo $encoded; 

?>



위의 예제를 약간 변경하여 언리얼 프로젝트에서 웹서버에 로그인하도록 연결한 예

로그인 기능을 담당하는 C++ 클래스에서 로그인 결과를 블루프린트에 통보하기 위해 C++에 함수의 원형을 선언하고  블루프린트에서 구현하였다. C++에 선언되어 있기 때문에 C++에서 호출이 가능하며 실행은 블루프린트에 정의된 함수가 실행된다


MyHttpActor.h (블루프린트에서 구현할 함수의 원형을 선언한다)

// Fill out your copyright notice in the Description page of Project Settings.


#pragma once


#include "CoreMinimal.h"

#include "GameFramework/Actor.h"

#include "Runtime/Online/HTTP/Public/Http.h"

#include "MyHttpActor.generated.h"


UCLASS(BlueprintType, Blueprintable)

class CPP_HTTP_API AMyHttpActor : public AActor

{

GENERATED_BODY()

public:

FHttpModule* Http;


UFUNCTION(BlueprintCallable, Category="HTTP")

void MyHttpCall(FString url); // http 요청에 사용할 함수


// http GET 요청 직후 호출되는 콜백함수

void OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);

//블루프린트에서 구현할 함수 선언

//이 방법을 사용하면 블루프린트에서 구현된 이벤트함수를 C++에서 호출할 수 있다

UFUNCTION(BlueprintImplementableEvent, Category="HTTP")

void PrintOnScreen(bool bLogin); // 정수 파라미터라면 int32형을 사용해야 한다


// 생성자 함수를 약간 변경한다

AMyHttpActor(const class FObjectInitializer& ObjectInitializer);


protected:

// Called when the game starts or when spawned

virtual void BeginPlay() override;


public:

// Called every frame

virtual void Tick(float DeltaTime) override;

};



MyHttpActor.cpp (블루프린트에서 구현한 함수를 C++에서 호출)

// Fill out your copyright notice in the Description page of Project Settings.


#include "MyHttpActor.h"

#include "../Public/MyHttpActor.h"


// Sets default values

AMyHttpActor::AMyHttpActor(const class FObjectInitializer& ObjectInitializer)

: Super(ObjectInitializer)

{

  // 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;

Http = &FHttpModule::Get();

}


// Called when the game starts or when spawned

void AMyHttpActor::BeginPlay()

{

Super::BeginPlay();

}


void AMyHttpActor::MyHttpCall(FString url)

{

TSharedRef<IHttpRequest> Request = Http->CreateRequest();

Request->OnProcessRequestComplete().BindUObject(this, &AMyHttpActor::OnResponseReceived);

//This is the url on which to process the request


Request->SetURL(url);


Request->SetVerb("GET");

Request->SetHeader(TEXT("User-Agent"), "X-UnrealEngine-Agent");

Request->SetHeader("Content-Type", TEXT("application/json"));

Request->ProcessRequest();

}


void AMyHttpActor::OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)

{

//웹서버로부터 응답된 내용을 화면에 디버그 문자열로 출력해본다

//GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, Response->GetContentAsString());

//Create a pointer to hold the json serialized data

TSharedPtr<FJsonObject> JsonObject;


//Create a reader pointer to read the json data

TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());


//Deserialize the json data given Reader and the actual object to deserialize

if (FJsonSerializer::Deserialize(Reader, JsonObject))

{

bool login = JsonObject->GetBoolField("login");

//이 클래스에서 선언하고 블루프린트에서 구현된 함수 호출

PrintOnScreen(login);

}

}


// Called every frame

void AMyHttpActor::Tick(float DeltaTime)

{

Super::Tick(DeltaTime);

}



위에 정의된 C++ 클래스를 기반으로 블루프린트 액터 클래스를 생성하고 C++에 선언된 PrintOnScreen 함수를 블루프린트에서 구현한다


BP_HttpActor



웹서버에서 로그인을 처리하는 PHP 스크립트

언리얼 프로젝트로부터 id, pwd 파라미터를 받아서 MySQL 데이터베이스를 검색하여 전달된 이용자 정보가 존재하는지 확인한다. 확인된 결과를 JSON 문자열로 표현하여 응답한다


unreal_login.php

<?php

header('Content-type: application/json; charset=UTF-8');

  $id = $_REQUEST["id"];

  $pwd = $_REQUEST["pwd"];


  $result = "";

  

  // DB 코드 시작

  $host='fdb24.awardspace.net';

  $user='2915954_user';

  $pass='2915954Database';

  $db='2915954_user';


  $arr = array();

  

  $conn = mysqli_connect($host,$user,$pass,$db);

  if ($conn->connect_error) {

$arr["error"] = true;

        echo json_encode($arr);

return;

  }

  if($conn) {

    $arr["connection"] = true;

  }

 

  $select_query = "SELECT * FROM Member WHERE memid='$id' AND mempwd='$pwd' ";


  $result_set = mysqli_query($conn, $select_query);


  if (mysqli_num_rows($result_set) > 0) {

$arr["login"] = true;

  } else {

$arr["login"] = false;

  }

  mysqli_close($conn);

  $json = json_encode($arr);

  echo $json;

?>


Posted by cwisky