ue4 C++ 实现socket非阻塞监听并回调主线程

假如创建一个线程,通过socket->Recv()阻塞效果实现监听接收,在监听到后需要调用蓝图中的某一个事件。

.h
#include "CoreMinimal.h"
#include "NetWorkProssingWeight.h"
#include "Async/AsyncWork.h"
#include "Runtime/Networking/Public/Networking.h"
#include "SocketManager.generated.h"
//通过动态单播委托的方式,通知正在监听的actor,好处是可以无视接收方的类型
DECLARE_DYNAMIC_DELEGATE(FHaveRecive);

UCLASS(BlueprintType)
class TEST_API USocketManager : public UObject
{
	GENERATED_BODY()
public:
	bool HaveMessage();
	UFUNCTION(BlueprintCallable, Category = "SocketManager")
		void BindListenReceive(FHaveRecive TregetFun);
	UFUNCTION(BlueprintCallable, Category = "SocketManager")
		void UnBindListen();//两个函数分别对应绑定和解绑
	UFUNCTION(BlueprintCallable, Category = "SocketManager")
		void SocketListenReceive();

private:
		bool HaveMessage();
		FSocket* SocketClient;
		
//省略socket基本功能实现
//省略socket基本功能实现
//省略socket基本功能实现
//重要的事说三遍
}

//创建一个负责监听的线程类,实现不阻塞主线程的接收,整个类定义的样例在AsyncWork.h中有写
class ReciveTask :public FNonAbandonableTask
{
	friend class FAutoDeleteAsyncTask<ReciveTask>;

	int32 ExampleData;

	FSocket* socket = nullptr;
	USocketManager* manager = nullptr;
	
	ReciveTask(FSocket* socket, USocketManager* manager)
	{
		this->manager = manager;
		this->socket = socket;
	}

	void DoWork();

	FORCEINLINE TStatId GetStatId() const
	{
		RETURN_QUICK_DECLARE_CYCLE_STAT(ExampleAutoDeleteAsyncTask, STATGROUP_ThreadPoolAsyncTasks);
	}
};
.cpp


#include "SocketManager.h"

bool USocketManager::HaveMessage()
{
	//检查socket连接状态,如果是断开连接就直接返回
	if (!SocketClient->GetConnectionState() == ESocketConnectionState::SCS_Connected)
		return false;
	ReciveCallback.Execute();
	return true;
}
void USocketManager::BindListenReceive(FHaveRecive TregetFun)
{
	ReciveCallback.Clear();
	ReciveCallback = TregetFun;
}

void USocketManager::UnBindListen()
{
	ReciveCallback.Clear();
}

void USocketManager::SocketListenReceive()
{//创建监听线程,结束后自动销毁
	(new FAutoDeleteAsyncTask<ReciveTask>(SocketClient, this))->StartBackgroundTask();
}

void ReciveTask::DoWork()
{
	int32 i = 0;
	socket->Recv(new uint8, 1, i, ESocketReceiveFlags::Peek);
	manager->HaveMessage();//负责调用委托
}

编译后进入蓝图
ue4 C++ 实现socket非阻塞监听并回调主线程_第1张图片

这样其实有个问题,如果想在接收后修改UI里的某个变量,整个程序会崩溃,所以要修改一下。

void ReciveTask::DoWork()
{
	int32 i = 0;
	socket->Recv(new uint8, 1, i, ESocketReceiveFlags::Peek);
	//这个函数可以在主线程中调用参数中的这些代码,这样就不会导致崩溃(也就是在子线程中调用主线程代码)
	AsyncTask(ENamedThreads::GameThread, [=]()
		{
			manager->HaveMessage();
		});
	
}

你可能感兴趣的:(UE4,学习,socket,多线程,c++)