Download

TCP Implementation -> Problem with TSharedRef<FInternetAddr>

Hello!

For now I am working on a project where I need to have communications between programs on another PC’s by TCP/IP.
My idea how to do this was:

  1. Create a socket.
  2. Set his connection parameters (address and port).
  3. Activate a timer which starts function which check whether the connection with the server is possible.
  4. Send simple message for now.

The problem is, as I mentioned in the topic is with TSharedRedd<FInsternetAddr>. I want to pass it to the function which is in the timer.

Below are my .cpp and .h codes.

.cpp



#include "TCP.h"


// Sets default values
ATCP::ATCP()
{
     // 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 ATCP::BeginPlay()
{
    Super::BeginPlay();
    LaunchTCP();
}

// Called every frame
void ATCP::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
    LaunchTCP();
}

bool ATCP::LaunchTCP() {

    UE_LOG(LogTemp, Warning, TEXT("TCP -> Starting..."));

    ConnectionSocket = CreateConnectionSocket();
    if (!ConnectionSocket) {
        UE_LOG(LogTemp, Error, TEXT("Cannot create socket."));
        return false;
    }

    FIPv4Address address;
    FIPv4Address::Parse(IP, address);

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

    ConnectionDelegate.BindUFunction(this, FName("CheckConnection"), addr);
    GetWorldTimerManager().SetTimer(ConnectionTimerHandle, ConnectionDelegate, 1.f, false);

    return true;
}

FSocket * ATCP::CreateConnectionSocket()
{
    FSocket* ConnectSock = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateSocket(NAME_Stream, TEXT("TCP"), false);
    return ConnectSock;
}

bool ATCP::CheckConnection(const TSharedRef<FInternetAddr>& addr)
{
    if (ConnectionSocket->Connect(*addr)) {
        UE_LOG(LogTemp, Warning, TEXT("Connection done."));
        GetWorldTimerManager().SetTimer(SendMessTimerHandle, this, &ATCP::SendMessage, 2.f, false);
        return true;
    }
    else {
        GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Waiting for the server...")));
        return false;
    }

}

void ATCP::SendMessage()
{
    FString serialized = "I am the message from UE4.";
    TCHAR* serializedChar = serialized.GetCharArray().GetData();
    int32 size = FCString::Strlen(serializedChar);
    int32 sent = 0;

    bool successful = ConnectionSocket->Send((uint8*)TCHAR_TO_UTF8(serializedChar), size, sent);

    if (successful) {
        UE_LOG(LogTemp, Warning, TEXT("Message Sent."));
    }

    return;
}



.h



#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Runtime/Networking/Public/Interfaces/IPv4/IPv4Address.h"
#include "Runtime/Sockets/Public/Sockets.h"
#include "Runtime/Engine/Public/TimerManager.h"
#include "Runtime/Sockets/Public/SocketSubsystem.h"
#include "Runtime/Core/Public/Templates/SharedPointer.h"
#include "Runtime/Sockets/Public/IPAddress.h"
#include "Runtime/Engine/Classes/Engine/Engine.h"
#include "TCP.generated.h"

UCLASS()
class TCPSTEPBYSTEP_API ATCP : public AActor
{
    GENERATED_BODY()

public:    
    // Sets default values for this actor's properties
    ATCP();

    UPROPERTY(EditAnywhere)
        FString IP = "127.0.0.1";

    UPROPERTY(EditAnywhere)
        int32 Port = 8890;

    FSocket* ConnectionSocket;


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

public:    
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    bool LaunchTCP();
    FSocket* CreateConnectionSocket();
    bool CheckConnection(const TSharedRef<FInternetAddr>& addr);
    void SendMessage();


private:
    FTimerDelegate ConnectionDelegate;
    FTimerHandle ConnectionTimerHandle;
    FTimerHandle SendMessTimerHandle;

};


Now program compiled successfully. But when played it crashes. In the crash log I can see problem with the ConnectionDelegate in the LauchTCP() method.

I tried to type UFUNCTION() before the bool CheckConnection(const TSharedRef& addr) but I can’t compile it. The error is →



Unrecognized type tsharedref - type must be UCLASS, USTRUCT or UENUM


Thanks in advance :slight_smile:

Used TCP for the past 3 projects. Couple of things that might be the problem:

  1. are you “sandwiching” your TCP headers like this?

https://answers.unrealengine.com/que…dword-int.html

Unreal and Winsock don’t get along due to naming and define collisions. Keep all your raw TCP stuff out of Unreal classes.

  1. You are putting TCP connections in an Actor which will be destroyed on level change. Is that intended or does your app never change levels? Our TCP connections live in the GameInstance which is never destroyed.
  1. What do you my with sandwiching? As you can see in my .h code above I included only Unreal in-built files like Sockets. I don’t use for example winsock.h.

  2. For now I just wanted to get the knowledge how to implement the communication. In case I will change the level - should I use the PlayerController class?