Files
UnrealEngine/Engine/Source/Runtime/Sockets/Public/MultichannelTcpReceiver.h
2025-05-18 13:04:45 +08:00

132 lines
2.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "NetworkMessage.h"
#include "HAL/RunnableThread.h"
#include "HAL/Runnable.h"
#include "MultichannelTcpGlobals.h"
class Error;
class FSocket;
/**
* Declares a delegate to be invoked when data has been received.
*
* The first parameter will hold the received data.
* The second parameter is the number of bytes received.
* The third parameter indicates whether byte swapping is needed on the received data.
*/
DECLARE_DELEGATE_ThreeParams(FOnMultichannelTcpReceive, const TArray<uint8>&, uint32, bool);
/**
* Implements a receiver for multichannel TCP sockets.
*/
class FMultichannelTcpReceiver
: public FRunnable
{
public:
/**
* Creates and initializes a new instance.
*
* @param InSocket The socket to receive from.
* @param InReceiveDelegate Delete to handle data as it becomes available, called from the receive thread.
*/
FMultichannelTcpReceiver( FSocket* InSocket, const FOnMultichannelTcpReceive& InReceiveDelegate )
: Socket(InSocket)
, ReceiveDelegate(InReceiveDelegate)
{
Thread = FRunnableThread::Create(this, TEXT("FMultichannelTCPReceiver"), 8 * 1024, TPri_AboveNormal);
}
/** Destructor. */
~FMultichannelTcpReceiver()
{
if (Thread)
{
Thread->Kill(true);
delete Thread;
}
}
public:
/**
* Gets the number of payload bytes actually sent to the socket.
*/
int32 GetBytesReceived()
{
return BytesReceived;
}
public:
// FRunnable interface
virtual bool Init( )
{
return true;
}
virtual uint32 Run( )
{
while (1)
{
// read a header and payload pair
FArrayReader Payload;
if (FNFSMessageHeader::ReceivePayload(Payload, FSimpleAbstractSocket_FSocket(Socket)) == false)
{
// if we failed to receive the payload, then the client is most likely dead, so, we can kill this connection
// @todo: Add more error codes, maybe some errors shouldn't kill the connection
break;
}
uint32 Magic;
Payload << Magic;
if (Magic != MultichannelMagic)
{
UE_LOG(LogMultichannelTCP, Error, TEXT("Wrong magic."));
break;
}
uint32 Channel;
Payload << Channel;
TArray<uint8> InnerPayload;
Payload << InnerPayload;
ReceiveDelegate.Execute(InnerPayload, Channel, Payload.ForceByteSwapping());
FPlatformAtomics::InterlockedAdd(&BytesReceived, InnerPayload.Num());
}
return 0;
}
virtual void Stop( ) { }
virtual void Exit( ) { }
private:
/** Holds the number of bytes received so far. */
int32 BytesReceived;
/** Holds the socket to use for communication. */
FSocket* Socket;
/** Holds the thread we are running on. */
FRunnableThread* Thread;
private:
/** Holds a delegate to be invoked when data has been received. */
FOnMultichannelTcpReceive ReceiveDelegate;
};