1.确保工程为C++工程,在项目工程的xx.Build.cs中加入Networking和Sockets模块。
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Networking", "Sockets"});
2.C++创建Actor,命名为UDPClient。
3.编写代码UDPClient.h和UDPClient.cpp实现UDP发送和接收功能。
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Runtime/Sockets/Public/Sockets.h"
#include "Sockets/Public/SocketSubsystem.h"
#include "Runtime/Networking/Public/Common/UdpSocketBuilder.h"
#include "Runtime/Networking/Public/Common/UdpSocketReceiver.h"
#include "Networking/Public/Interfaces/IPv4/IPv4Address.h"
#include "UDPClient.generated.h"
UCLASS()
class MYBLANK_API AUDPClient : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AUDPClient();
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;
public:
FSocket* udpSocket;
//远程的地址
TSharedPtr<FInternetAddr> RemoteAddr;
UFUNCTION(BlueprintCallable, Category = "UDP")
bool CreateUdp(const FString& socketName, const FString& targetIP, const int32 targetPort, const int32 selfPort);
UFUNCTION(BlueprintCallable, Category = "UDP")
bool SendMsg(FString msg);
UFUNCTION(BlueprintCallable, Category = "UDP")
void RecvMsg(bool& result, FString& msg);
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "UDPClient.h"
// Sets default values
AUDPClient::AUDPClient()
{
// 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;
udpSocket = NULL;
}
// Called when the game starts or when spawned
void AUDPClient::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AUDPClient::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AUDPClient::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
if (udpSocket)
{
udpSocket->Close();
ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(udpSocket);
}
}
bool AUDPClient::CreateUdp(const FString& socketName, const FString& targetIP, const int32 targetPort, const int32 selfPort)
{
bool bIsValid;
RemoteAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
RemoteAddr->SetIp(*targetIP, bIsValid);
RemoteAddr->SetPort(targetPort);
if (!bIsValid)
{
UE_LOG(LogTemp, Warning, TEXT("CreateUdp>> IP address was not valid! "), *targetIP);
return false;
}
int32 BufferSize = 2 * 1024 * 1024;
FIPv4Endpoint Endpoint(FIPv4Address::Any, selfPort); //所有ip地址本地
udpSocket = FUdpSocketBuilder(*socketName)
.AsReusable()
.WithBroadcast() // 广播
.WithSendBufferSize(BufferSize)
.AsNonBlocking()
.BoundToEndpoint(Endpoint)
.WithReceiveBufferSize(BufferSize);
udpSocket->SetSendBufferSize(BufferSize, BufferSize);
udpSocket->SetReceiveBufferSize(BufferSize, BufferSize);
return bIsValid;
}
bool AUDPClient::SendMsg(FString msg)//发送消息
{
if (!udpSocket)
{
UE_LOG(LogTemp, Warning, TEXT("No udpSocket"));
return false;
}
int32 BytesSent = 0;
FString serialized = msg;
TCHAR* serializedChar = serialized.GetCharArray().GetData();
int32 size = FCString::Strlen(serializedChar);
int32 sent = 0;
udpSocket->SendTo((uint8*)TCHAR_TO_UTF8(serializedChar), size, BytesSent, *RemoteAddr);
if (BytesSent < 0)
{
const FString Str = "Socket is valid but the receiver received 0 bytes, make sure it is listening properly!";
UE_LOG(LogTemp, Error, TEXT("%s"), *Str);
return false;
}
UE_LOG(LogTemp, Warning, TEXT("SendMsg Succcess! INFO msg = %s "), *msg);
return true;
}
void AUDPClient::RecvMsg(bool& result,FString& msg)//接收消息
{
if (!udpSocket)
{
UE_LOG(LogTemp, Warning, TEXT("No udpSocket"));
result = false;
}
TSharedRef<FInternetAddr> targetAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
TArray<uint8> ReceivedData;//定义一个接收器
uint32 Size;
if (udpSocket->HasPendingData(Size))
{
result = true;
msg = "";
uint8* Recv = new uint8[Size];
int32 BytesRead = 0;
ReceivedData.SetNumUninitialized(FMath::Min(Size, 65507u));
udpSocket->RecvFrom(ReceivedData.GetData(), ReceivedData.Num(), BytesRead, *targetAddr);//创建远程接收地址
char ansiiData[1024];
memcpy(ansiiData, ReceivedData.GetData(), BytesRead);//拷贝数据到接收器
ansiiData[BytesRead] = 0; //判断数据结束
FString debugData = UTF8_TO_TCHAR(ansiiData); //字符串转换
msg = debugData;
}
else
{
result = false;
}
}
FUdpSocketBuilder Functions介绍: