Compiler crashes when trying to extend class FRunnableThread
2>EXEC : error : Couldn't find parent type for 'ServerThread' named 'FRunnableThread' in current module or any other module parsed so far.
2>Error : Failed to generate code for RenderServerEditor - error code: OtherCompilationError (5)
2> UnrealHeaderTool failed for target 'RenderServerEditor' (platform: Win64, module info: D:\Unreal_Projects\RenderServer\Intermediate\Build\Win64\RenderServerEditor\Development\UnrealHeaderTool.manifest).
2>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.MakeFile.Targets(38,5): error MSB3073: The command ""D:\UnrealEngine4\Epic Games\4.9\Engine\Build\BatchFiles\Build.bat" RenderServerEditor Win64 Development "D:\Unreal_Projects\RenderServer\RenderServer.uproject" -rocket -waitmutex" exited with code -1.
This is the code that crashes
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreGlobals.h"
#include "SocketServer.h"
#include "Object.h"
#include "ServerThread.generated.h"
/**
*
*/
UCLASS()
class RENDERSERVER_API UServerThread : public FRunnableThread;
{
GENERATED_BODY()
};
I think what you want to do is to create a run-able that holds it’s own thread. If yes you should not inherit from FRunableThread, you have to use it. The next snippet is a sample implementation of a server that listens to connections on a separate thread.
// RunableServer.h
//
// Copyright (c) 2015 Moritz Wundke
// MIT License
//
#pragma once
#include "Networking.h"
#include "TcpListener.h"
// Default endpoint for the server
#define DEFAULT_ENDPOINT FIPv4Endpoint(FIPv4Address(127, 0, 0, 1), 5005)
/**
* Server listening on a TCP socket
*/
class FRunableServer
: public FRunnable
{
public:
FUnrealEdRemoteServer();
~FUnrealEdRemoteServer();
/** FRunnable init */
virtual bool Init() override;
/** FRunnable loop */
virtual uint32 Run() override;
bool HandleListenerConnectionAccepted(class FSocket* ClientSocket, const FIPv4Endpoint& ClientEndpoint);
/**
* Checks whether the listener is listening for incoming connections.
*
* @return true if it is listening, false otherwise.
*/
bool IsActive() const
{
return (!Stopping);
}
virtual void Stop() override
{
Stopping = true;
}
virtual void Exit() override { }
private:
class FTcpListener *Listener = NULL;
/** Current clients and pending to get accepted clients */
TQueue<class FSocket*, EQueueMode::Mpsc> PendingClients;
TArray<class FSocket*> Clients;
/** Used to tell that the thread is stopping */
bool Stopping;
/** Connection thread, used to not block the editor when waiting for connections */
FRunnableThread* Thread = NULL;
/** Basic message handling, your implementation will be in here */
FString HandleClientMessage(const FSocket *Socket, const FString& Message);
};
And the CPP
// RunableServer.cpp
//
// Copyright (c) 2015 Moritz Wundke
// MIT License
//
#include "RunableServer.h"
#include "Runtime/Core/Public/Misc/CString.h"
FRunableServer::FRunableServer()
: Listener(NULL), Thread(NULL)
{
Thread = FRunnableThread::Create(this, TEXT("FRunableServer"), 8 * 1024, TPri_Normal);
}
FRunableServer::~FRunableServer()
{
// Stop the runnable
Stop();
// Stop accepting clients first
if (Listener != NULL)
{
Listener->Stop();
delete Listener;
Listener = NULL;
}
// Kill all pending connections and current connections
if (!PendingClients.IsEmpty())
{
FSocket *Client = NULL;
while (PendingClients.Dequeue(Client))
{
Client->Close();
}
}
for (TArray<class FSocket*>::TIterator ClientIt(Clients); ClientIt; ++ClientIt)
{
(*ClientIt)->Close();
}
// And last but not least stop the main thread
if (Thread != NULL)
{
Thread->Kill(true);
delete Thread;
}
}
bool FRunableServer::HandleListenerConnectionAccepted(class FSocket* ClientSocket, const FIPv4Endpoint& ClientEndpoint)
{
PendingClients.Enqueue(ClientSocket);
return true;
}
bool FRunableServer::Init()
{
if (Listener == NULL)
{
Listener = new FTcpListener(DEFAULT_ENDPOINT);
Listener->OnConnectionAccepted().BindRaw(this, &FUnrealEdRemoteServer::HandleListenerConnectionAccepted);
Stopping = false;
}
return (Listener != NULL);
}
/** Send a string message over to a socket */
bool SendMessage(FSocket *Socket, const FString& Message)
{
check(Socket);
int32 BytesSent = 0;
return Socket->Send((uint8*)TCHAR_TO_UTF8(*Message), Message.Len(), BytesSent);
}
/** Receive a string message from a socket */
bool RecvMessage(FSocket *Socket, uint32 DataSize, FString& Message)
{
check(Socket);
FArrayReaderPtr Datagram = MakeShareable(new FArrayReader(true));
Datagram->Init(FMath::Min(DataSize, 65507u));
int32 BytesRead = 0;
if (Socket->Recv(Datagram->GetData(), Datagram->Num(), BytesRead))
{
char* Data = (char*)Datagram->GetData();
Data[BytesRead] = '\0';
Message = UTF8_TO_TCHAR(Data);
return true;
}
return false;
}
uint32 FRunableServer::Run()
{
while (!Stopping)
{
if (!PendingClients.IsEmpty())
{
FSocket *Client = NULL;
while (PendingClients.Dequeue(Client))
{
Clients.Add(Client);
}
}
// remove closed connections
for (int32 ClientIndex = Clients.Num() - 1; ClientIndex >= 0; --ClientIndex)
{
if (Clients[ClientIndex]->GetConnectionState() != SCS_Connected)
{
Clients.RemoveAtSwap(ClientIndex);
}
}
// Poll data from every connected client
for (TArray<class FSocket*>::TIterator ClientIt(Clients); ClientIt; ++ClientIt)
{
FSocket *Client = *ClientIt;
uint32 DataSize = 0;
while (Client->HasPendingData(DataSize))
{
FString Request;
if (RecvMessage(Client, DataSize, Request))
{
FString Response = HandleClientMessage(Client, Request);
SendMessage(Client, Response);
}
}
}
FPlatformProcess::Sleep(0.2f);
}
return 0;
}
FString FRunableServer::HandleClientMessage(const FSocket *Socket, const FString& Message)
{
bool bProcessed = false;
FString Response;
// TODO: Here goes your code to handle the actual message
return bProcessed ? TEXT("OK") : TEXT("KO");
}
NOTE: The code might need some tweaks but you should see how I’m using the thread in here
I know this post has been closed over a year ago, but I just had a few questions and hoped you can answer them. How do you create this thread, and does this work for the multithreading part (also with closing the thread)?