top of page

Outil "Search IP"

Récupérer une IP de manière simple et efficace

Technologies utilisées :

- C++ pour la création de la requête elle-même, le traitement des réponses serveur ainsi que la création de fonctions callables par blueprint.

- Blueprint pour l'affichage des données et les appels de fonction.

- Json pour la désérialisation de la réponse serveurHTTP pour l'envoi de requêtes.

Prérequis :

Pour commencer il faut que vous ayez un projet CPP vierge, possédez un Visual Studio à jour ainsi que la version 4.15 d'Unreal Engine 4. Cette manière de faire peut fonctionner certainement sur des versions antérieures d'Unreal, cependant, la version utilisée dans les exemples est la version 4.15. Puis bon, 50% de temps de compilation en moins quoi...

Étape 1 - Configurer le project.build :

La première étape consiste à ajouter au [projectName].build.cs l'utilisation des modules Http, Json et JsonUtilities. Sans cet ajout, il sera impossible de builder et donc, d'utiliser ces modules. Le module HTTP concerne tout ce qui va toucher aux requêtes en elle-même, le traitement des réponses (Retour en Json, Code HTTP, etc) ainsi que la gestion des erreurs.

​

Le module Json va servir à récupérer une réponse au format Json et permettre la lecture et l'écriture de ce format.

​

Quand au module JsonUtilities, il s'agit d'un panel de fonctions très utile. Ici nous allons utiliser la fonction de lecture et de désérialisation.

​

 

​

 

 

 

 

 

 

 

 

 

 

 

Pour finir avec l'activation d'HTTP, un petit ajout dans le DefaultEngine

s'impose :

​

[HTTP]
HttpTimeout=300
HttpConnectionTimeout=-1
HttpReceiveTimeout=-1
HttpSendTimeout=-1
HttpMaxConnectionsPerServer=16
bEnableHttp=true
bUseNullHttp=false
HttpDelayTime=0

 

​

​

​

Étape 2 : Mise en place de la class IPManager

La seconde étape va être de créer une class C++ de type Actor.h. Ici j'ai choisi de nommer ma class "IPManager". Maintenant dans le header, il faut renseigner le fait que nous allons utiliser Http.h ainsi que JsonOjectConverter.h.

Étape 3 : Mise en place des variables et des fonctions

Dans le cadre de cet outil, nous aurons besoin de  plusieurs variables et fonctions.

Nos variables serons placées en private afin de respecter la portée des variables du C++ et que l'URL ne soit pas modifiable via un Outil tierce.

L'adresse IP étant composée de nombres et de points, nous allons la stocker dans un FString IPAdresse.

​

Une requête HTTP pointe forcément vers une URL. Nous allons stocker cette URL dans une variable FString URLSearchIP.

​

Chaque requête HTTP retourne une réponse sous forme de code. Par exemple, une erreur 404 qui correspond à un élément introuvable. Ce code sera stocké dans une variable int32 ResponseCode.

​

Pour utiliser le module HTTP, il faut créer un objet de type

FHttpModule* que nous nommerons Http et qui sera initialisé dans le constructeur de notre class de la manière suivante : Http = &FHttpModule::Get();

​

​

​

​

​

​

​

​

​

​

Du côté des fonctions, nous aurons besoin d'une fonction

public FString GetClientIP() qui retournera l'adresse IP récupérée. Cette fonction a besoin d'être public et utilisable via l’éditeur Blueprint.

Chaque requête prend deux fonctions. Une fonction pour fabriquer et envoyer la requête et une fonction pour traiter la réponse du serveur quand la requête est complétée. La requête doit être utilisable en Blueprint. En revanche, la réponse doit être privée et ne peut être appelée que par un event lié à la complétion de la requête :

​

- void SearchIPRequest(); //Construit et lance la requête

- void SearchIPResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful); //Traite la réponse du serveur

​

​

​

​

​

Étape 4 - Paramétrer l'URL et Construire la requête :

La préparation est maintenant terminée. Place au contenu des fonctions.

Dans le cadre de cet exercice, nous souhaitons communiquer avec un serveur distant afin que celui-ci nous renvoie une réponse contenant notre propre adresse Ip externe (Et non pas interne vu que nous ne sommes pas en réseau LAN).

​

Le mécanisme est le suivant :

. Au clic sur un bouton, SearchIPRequest est appelé.

. Une requête HTTP pointant vers https://api.ipify.org?format=json  et utilisant la méthode GET est envoyée.

. Le serveur répond et nous renvoie une chaîne de caractères contenant du Json.

. SearchIPResponse est appelé et traite le Json pour en extraire l'adresse IP, puis stock l'adresse dans la variable adéquate.

. Le blueprint lance la fonction GetClientIP() et récupère l'adresse IP, puis l'affiche à l'écran du joueur.

​

La première chose à faire, en mettant de côté la partie Blueprint, va être de renseigner l'URL. Renseignez la variable URLSearchIP avec l'URL donné plus haut.

​

Maintenant, direction le IPManager.cpp. Pour construire la requête, nous allons utilisés notre objet nommé Http.

​

Note : Afin de ne pas alourdir cet exercice, la partie sécurité et gestion des erreurs est volontairement mise de côté.

​

A partir d'Http, nous allons créer une requête nommée Request.

​

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

​

Puis nous allons paramétrés l'objet Request :

​

Request->SetURL(URLSearchIP); //URL du serveur distant.

Request->SetVerb("GET"); //Methode de communication. Get, Post ou Put.

Request->SetHeader("Accept", "application/json"); //Le type de données autorisées. Ici nous recevrons du Json.

Request->ProcessRequest(); //Démarre la requête.

​

Et enfin le plus important, la fonction qui sera appelée lorsque la requête sera terminée :

​

Request->OnProcessRequestComplete().BindUObject(this, &AIPManager::SearchIPResponse);

 

 

 

 

 

 

​

Étape 5 - Construction de la réponse :

Lorsque la requête est complétée, le serveur va renvoyer deux informations qui seront contenues dans un objet FHttpResponsePtr.

​

Dans notre fonction réponse, nous allons récupérer le code HTTP (Ce code sert à traiter les erreurs principalement.) :

​

ResponseCode = Response->GetResponseCode();

​

Ensuite, nous allons créer un objet de type TSharedPtr<FJsonObject> qui va servir à récupérer la chaîne de caractères renvoyée par le serveur et de reconstituer le Json. Cette action est appelée "Serialization".

​

TSharedPtr<FJsonObject> JsonObject;

​

Maintenant nous allons lire le Json contenu dans la réponse.

​

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

​

Tout ce qu'il nous reste à faire, est de chercher l'objet Json qui nous intéresse. Ici c'est l'objet "ip" que nous voulons. Ensuite cet objet sera transformé en chaîne de caractère scompréhensible par le C++. Désérialisons :

​

if (FJsonSerializer::Deserialize(Reader, JsonObject))
    {
        IPAdresse = JsonObject->GetStringField("ip");
    }

​

La fonction réponse est maintenant prête à l'emploi.

​

Avant de passer à la partie Blueprint, pensez à paramétrer la fonction GetClientIp pour qu'elle retourne IPAdresse.

​

Étape 6 - Création du widget et affichage de l'IP

Pour la suite, vous aurez besoin d'un widget blueprint contenant un bouton et un texte mis en variable.

​

Afin de pouvoir utiliser notre class directement dans notre WBP il faut générer un BP Actor depuis le C++. C'est à dire, dans l'éditor, cliquez droit sur Content, ouvrez le dossier C++, cliquez droit sur votre class puis Create Blueprint.

 

​

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

​

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

​

 

 

 

 

 

 

 

 

Ajoutez votre BP_IPManager à la scène. Depuis votre WBP, vous pouvez rechercher votre actor et le mettre dans une variable (Clic droit sur As actor -> Promote to variable).

 

​

 

 

 

 

​

 

 

​

​

​

​

​

Activez l'event OnClicked de votre button. Faites un cast to IPmanager depuis votre référence. A partir de là, vous pouvez lancer les fonctions SearchIPRequest et GetClient. Il ne vous reste plus qu'à lancer votre WBP depuis le levelblueprint ou une touche d'action pour chercher votre IP.

​

​

​

​

​

​

Ma chaƮne

Ma chaƮne

Ma chaƮne
Rechercher une vidƩo...
bp_from_cpp

bp_from_cpp

00:07
Lire la vidƩo

A ce stade, nous avons donc une requête et un widget fonctionnel. Mais, car oui il y a un gros mais.... Notre requête est dite, Asynchrone. Non, ce n'est pas une insulte.

 

En fait c'est plutôt logique. Une requête HTTP met un certain laps de temps à se terminer. C'est un temps très court, en millièmes de seconde. Le problème, c'est que notre Widget n'attend pas la fin de la requête pour demander la variable IPAdresse. Le GetClientIp() est donc exécuté entre le début de la requête et la gestion de la réponse serveur.

Etape Finale - Synchronisation :

Nous avons compris le problème de l'asynchronisation. Il y a deux possibilités : soit l'on met un Delay entre le lancement de la requête et le GetClientIp, soit la requête et la réponse notifient leurs avancement.

​

Le premier choix, bien que rapide à mettre en place, alourdit dramatiquement les requêtes. Imaginez un formulaire de Login qui durerait 2s pour chaque joueur, peut importe si vous avez la fibre ou un 56K. Pire, une personne met 2.1s au lieu des 2s du Delay et ne peut se loguer.

​

Pour cet exercice, j'ai donc choisi le second choix.

​

Pour synchroniser notre WBP à notre requête, nous avons besoin de connaître deux états. Si la requête est en cours ou non et si la réponse est traitée ou non. Ainsi nous allons créer deux booléens : IsRunning, IsBusy. Ces deux variables seront en public, visibles et modifiables via Blueprint.

​

Quand la requête est lancée, la variable IsBusy = true. Quand la réponse est traitée, IsBusy = false.

​

Côté C++, nous en avons terminé. Pensez à bien compiler avant le blueprint.

​

Retournons donc dans notre widget. Tout ce qui est après SearchIPRequest, nous allons le mettre de côté. A la place, il va falloir allez chercher le Set IsRunning et mettre la variable sur true.

​

​

Ensuite, nous allons ajouter 2 branch reliées à EventTick. La première vérifie si IsRunning est true. Si oui, la seconde branch vérifie si IsBusy est false. Si IsBusy est false, GetClientIp est exécuté et IsRunning est mis sur false.

​

​

Cet exercice touche à sa fin. Félicitations, vous avez une requête synchronisée prête à l'emploi.

​

J'espère que ça vous à plu. N'hésitez pas à partager et à laisser un commentaire.

​

Amicalement,

Arkas

​

​

​

bottom of page