Announcement

Collapse
No announcement yet.

TCP Socket Listener, Receiving Binary Data into UE4 From a Python Script!

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    #46
    Thank you Nico de Poel for your post.
    I used code sample you provided and it worked like miracle, i was finally able to receive expected data. Connection broke afterwards, but I'll figure it out,
    One more thing, probably not from this topic, but I am wondering if you could help with one more thing, or recomment some other post. I want to create standalone plugin, with tcp listener and i cant figure out, how to use actor classes (put them in actual game and make them work), which I created in plugin folders.
    Last edited by Brano Popadic; 02-21-2017, 05:10 AM.

    Comment


      #47
      A quick question, is it possible to access the dev lan address on a PS4, i'm trying to setup some automation that requires a tcp connection.

      Thanks

      Comment


        #48
        Hi Rama, Do you know if it is possible or how to connect to a PS4 Dev Lan, i'm trying to set up some automation software that requires this connection.

        Thanks

        Dave

        Comment


          #49
          TCP Receiver and Sender

          Dear Unreal Community,

          First of all thank you very much Rama for your great work!
          Cause we've had some trouble with the TCP Connection between Unreal Engine and MATLAB we've extended (Sending feature) and did some changes to the RAMA Code
          to work with the actual Unreal Engine and want to share the code with you. We used it inside an Actor Class - smarter would be a plugin ... maybe there's some time in the future.

          It's written quick & dirty any recommendations are welcome!

          1. Do not forget to Add the Dependencies in *YourClassName*.build.cs => AND right-click on the C++ Project File => Right-click on the .uproject file. => Select "Generate Visual Studio project files". Re-open the Project (Unreal & VisualStudio) after before trying to compile!

          Code:
          PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Sockets", "Networking" });
          2. Header-File

          Code:
          // Fill out your copyright notice in the Description page of Project Settings.
          
          #pragma once
          
          #include "GameFramework/Actor.h"
          #include "Networking.h"
          #include "MyActorTCP.generated.h"
          
          UCLASS()
          class VECTION_API AMyActorTCP : public AActor
          {
          	GENERATED_BODY()
          
          public:
          	// Sets default values for this actor's properties
          	AMyActorTCP();
          
          protected:
          	// Called when the game starts or when spawned
          	virtual void BeginPlay() override;
          	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
          
          
          public:
          	// Called every frame
          	virtual void Tick(float DeltaTime) override;
          	FSocket* ListenerSocket;
          	FSocket* ConnectionSocket;
          	FIPv4Endpoint RemoteAddressForConnection;
          
          	FTimerHandle TCPSocketListenerTimerHandle;
          	FTimerHandle TCPConnectionListenerTimerHandle;
          
          	bool StartTCPReceiver(
          		const FString& YourChosenSocketName,
          		const FString& TheIP,
          		const int32 ThePort
          		);
          
          	FSocket* CreateTCPConnectionListener(
          		const FString& YourChosenSocketName,
          		const FString& TheIP,
          		const int32 ThePort,
          		const int32 ReceiveBufferSize = 2 * 1024 * 1024
          		);
          
          	//Timer functions, could be threads
          	void TCPConnectionListener(); 	//can thread this eventually
          	FString StringFromBinaryArray(TArray<uint8> BinaryArray);
          	void TCPSocketListener();		//can thread this eventually
          
          
          									//Format String IP4 to number array
          	bool FormatIP4ToNumber(const FString& TheIP, uint8(&Out)[4]);
          
          	UFUNCTION(BlueprintCallable, Category = "TCPServer")
          		bool LaunchTCP();
          
          	UFUNCTION(BlueprintCallable, Category = "TCPServer")
          		void TCPSend(FString message);
          
          	UFUNCTION(BlueprintImplementableEvent, Category = "TCPServer")
          		void recievedMessage(const FString &message);
          };
          3. CPP File

          Code:
          #include "Vection.h"
          #include <string>
          #include "MyActorTCP.h"
          
          
          // Sets default values
          AMyActorTCP::AMyActorTCP()
          {
           	// 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 AMyActorTCP::BeginPlay()
          {
          	Super::BeginPlay();
          }
          
          void AMyActorTCP::EndPlay(const EEndPlayReason::Type EndPlayReason)
          {
          	Super::EndPlay(EndPlayReason);
          	UWorld* World = GetWorld();
          
          	GetWorld()->GetTimerManager().ClearTimer(TCPConnectionListenerTimerHandle);
          	GetWorld()->GetTimerManager().ClearTimer(TCPSocketListenerTimerHandle);
          
          	if (ConnectionSocket != NULL) {
          		ConnectionSocket->Close();
          	}
          	if (ListenerSocket != NULL) {
          		ListenerSocket->Close();
          	}
          
          }
          
          // Called every frame
          void AMyActorTCP::Tick(float DeltaTime)
          {
          	Super::Tick(DeltaTime);
          
          }
          
          // TCP Server Code
          bool AMyActorTCP::LaunchTCP()
          {
          	if (!StartTCPReceiver("RamaSocketListener", "127.0.0.1", 62))
          	{
          		return false;
          	}
          	return true;
          }
          
          //Rama's Start TCP Receiver
          bool AMyActorTCP::StartTCPReceiver(
          	const FString& YourChosenSocketName,
          	const FString& TheIP,
          	const int32 ThePort
          	) {
          	//Rama's CreateTCPConnectionListener
          	ListenerSocket = CreateTCPConnectionListener(YourChosenSocketName, TheIP, ThePort);
          
          	//Not created?
          	if (!ListenerSocket)
          	{
          		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("StartTCPReceiver>> Listen socket could not be created! ~> %s %d"), *TheIP, ThePort));
          		return false;
          	}
          
          	//Start the Listener! //thread this eventually
          
          
          	UWorld* World = GetWorld();
          	World->GetTimerManager().SetTimer(TCPConnectionListenerTimerHandle, this, &AMyActorTCP::TCPConnectionListener, 1.0f, true);
          	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("StartTCPReceiver>> Listen socket created")));
          	return true;
          }
          //Format IP String as Number Parts
          bool AMyActorTCP::FormatIP4ToNumber(const FString& TheIP, uint8(&Out)[4])
          {
          	//IP Formatting
          	TheIP.Replace(TEXT(" "), TEXT(""));
          
          	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          	//						   IP 4 Parts
          
          	//String Parts
          	TArray<FString> Parts;
          	TheIP.ParseIntoArray(Parts, TEXT("."), true);
          	if (Parts.Num() != 4)
          		return false;
          
          	//String to Number Parts
          	for (int32 i = 0; i < 4; ++i)
          	{
          		Out[i] = FCString::Atoi(*Parts[i]);
          	}
          
          	return true;
          }
          //Rama's Create TCP Connection Listener
          FSocket* AMyActorTCP::CreateTCPConnectionListener(const FString& YourChosenSocketName, const FString& TheIP, const int32 ThePort, const int32 ReceiveBufferSize)
          {
          	uint8 IP4Nums[4];
          	if (!FormatIP4ToNumber(TheIP, IP4Nums))
          	{
          		return false;
          	}
          
          	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          
          	//Create Socket
          	FIPv4Endpoint Endpoint(FIPv4Address(IP4Nums[0], IP4Nums[1], IP4Nums[2], IP4Nums[3]), ThePort);
          	FSocket* ListenSocket = FTcpSocketBuilder(*YourChosenSocketName)
          		.AsReusable()
          		.BoundToEndpoint(Endpoint)
          		.Listening(8);
          
          	//Set Buffer Size
          	int32 NewSize = 0;
          	ListenSocket->SetReceiveBufferSize(ReceiveBufferSize, NewSize);
          
          	//Done!
          	return ListenSocket;
          }
          //Rama's TCP Connection Listener
          void AMyActorTCP::TCPConnectionListener()
          {
          
          	//~~~~~~~~~~~~~
          	if (!ListenerSocket) return;
          	//~~~~~~~~~~~~~
          	//Remote address
          	TSharedRef<FInternetAddr> RemoteAddress = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
          	bool Pending;
          
          	// handle incoming connections
          	ListenerSocket->HasPendingConnection(Pending);
          
          	if (Pending)
          	{
          		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          		//Already have a Connection? destroy previous
          		if (ConnectionSocket)
          		{
          			ConnectionSocket->Close();
          			ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ConnectionSocket);
          		}
          		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          
          		//New Connection receive!
          		ConnectionSocket = ListenerSocket->Accept(*RemoteAddress, TEXT("RamaTCP Received Socket Connection"));
          
          
          		if (ConnectionSocket != NULL)
          		{
          			//Global cache of current Remote Address
          			RemoteAddressForConnection = FIPv4Endpoint(RemoteAddress);
          
          			//can thread this too
          			UWorld* World = GetWorld();
          
          			World->GetTimerManager().SetTimer(TCPSocketListenerTimerHandle, this, &AMyActorTCP::TCPSocketListener, 0.1f, true);
          		}
          	}
          }
          
          //Rama's String From Binary Array
          FString AMyActorTCP::StringFromBinaryArray(TArray<uint8> BinaryArray)
          {
          
          	//Create a string from a byte array!
          	const std::string cstr(reinterpret_cast<const char*>(BinaryArray.GetData()), BinaryArray.Num());
          
          	return FString(cstr.c_str());
          
          	//BinaryArray.Add(0); // Add 0 termination. Even if the string is already 0-terminated, it doesn't change the results.
          	// Create a string from a byte array. The string is expected to be 0 terminated (i.e. a byte set to 0).
          	// Use UTF8_TO_TCHAR if needed.
          	// If you happen to know the data is UTF-16 (USC2) formatted, you do not need any conversion to begin with.
          	// Otherwise you might have to write your own conversion algorithm to convert between multilingual UTF-16 planes.
          	//return FString(ANSI_TO_TCHAR(reinterpret_cast<const char*>(BinaryArray.GetData())));
          }
          
          void AMyActorTCP::TCPSend(FString ToSend) {
          	ToSend = ToSend + LINE_TERMINATOR; //For Matlab we need a defined line break (fscanf function) "\n" ist not working, therefore use the LINE_TERMINATOR macro form UE
          
          	TCHAR *SerializedChar = ToSend.GetCharArray().GetData();
          	int32 Size = FCString::Strlen(SerializedChar);
          	int32 Sent = 0;
          	uint8* ResultChars = (uint8*)TCHAR_TO_UTF8(SerializedChar);
          
          	if (!ConnectionSocket->Send(ResultChars, Size, sent)) {
          		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Error sending message")));
          	}
          
          }
          
          //Rama's TCP Socket Listener
          void AMyActorTCP::TCPSocketListener()
          {
          	//~~~~~~~~~~~~~
          	if (!ConnectionSocket) return;
          	//~~~~~~~~~~~~~
          
          
          	//Binary Array!
          	TArray<uint8> ReceivedData;
          
          	uint32 Size;
          	while (ConnectionSocket->HasPendingData(Size))
          	{
          		ReceivedData.Init(FMath::Min(Size, 65507u), Size);
          
          		int32 Read = 0;
          		ConnectionSocket->Recv(ReceivedData.GetData(), ReceivedData.Num(), Read);
          	}
          	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          
          	if (ReceivedData.Num() <= 0)
          	{
          		return;
          	}
          
          	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          	//						Rama's String From Binary Array
          	const FString ReceivedUE4String = StringFromBinaryArray(ReceivedData);
          	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          	recievedMessage(ReceivedUE4String);
          
          	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("As String Data ~> %s"), *ReceivedUE4String));
          }

          Comment


            #50
            [MENTION=29593]PHi.Wop[/MENTION]

            Thank you for sharing! I am linking your post in the wiki!



            Rama
            UE4 Marketplace: Melee Weapon Plugin & Compressed Binary Save System Plugin | Rama's C++ AI Jumping Videos | Vertex Snap Editor Plugin

            ♥ Rama

            Comment


              #51
              Thank you for the code. I used your code and could get tcp connection in Unreal but still could not receive the data yet. I wrote the tcp sender script in python.

              Code:
              import socket
              
              s = None
              
              def openConnection(TCP_PORT=8888):
                  TCP_IP = '127.0.0.1'
                  BUFFER_SIZE = 1024
                  global s
              
                  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                  s.connect((TCP_IP, TCP_PORT))
              
              def sendMessage(MESSAGE):
                  s.send(MESSAGE)
              
              def closeConnection():
                  s.close()
              I tested by let my unreal project in play mode.
              and in python

              Code:
              sender.openConnection(8888)
              And I see "Connection accepted from ..."

              but when running
              Code:
              sender.sendMessage("ASdfsdf")
              No log about received data. It looks like when tcp was connected, `HandleConnectionAccepted` was called and no data at that time yet. When receiving message, no callback is called.

              Since I am new to tcp so not sure if I test it right.

              I would appreciate if you could show your script for testing.

              Thanks,
              Zack
              Last edited by ZackZhang; 05-17-2017, 01:58 PM.

              Comment


                #52

                hi Rama,

                Thanks very much for your great sharing.

                I am using your code to receive data from H5 client and I can accept the connection but H5 client cannot shakehands successfully. Do you any idea? Am I miss something?

                Comment


                  #53
                  I wanted to mention that I referred to this thread in another ( https://forums.unrealengine.com/deve...-works-on-4-19 ).
                  If anybody has a TCP Listener that 1. works in 4.19 and perhaps 2. Run on its own thread I would like to see the code. I have not been able to get any of the pieces of code working that were shared in this thread. Makes me wonder how things will go in 4.20 with all the changes.

                  Comment


                    #54
                    Hello all.

                    I've been on a deep dive lately trying to learn the process of having two applications communicate with each other. All of this information is great and I am trying to process everything that's been given. I have some questions that might seem basic. My main goal is to have the ability to execute python scripts from Maya to Unreal.

                    Is it possible to communicate to other software through unreal without a plugin? Does Unreal have a built in structure to utilize?

                    My first test is to send a simple HelloWorld.py from maya and try and get it over to Unreal. I would appreciate any pointers or feedback on how to approach this.

                    Thanks!

                    Comment


                      #55
                      Is this supposed to work with later versions of the Engine? I am currently on 4.24 and trying to send one message/data from a client to another client.
                      "Networking.h" no longer seems to exist.
                      I have tried including Sockets.h, SocketSubsystem.h, Runtime/Networking/Public/Interfaces/IPv4/IPv4Address.h
                      Not having any luck with building the c++ code.

                      Comment

                      Working...
                      X