UE4_UDP广播_服务端(纯c++)_客户端(UE4)_1

首先搞明白什么是广播,在其他大佬的博文中在发送端,把发送的ip设置为255.255.255.255,就是广播地址,如果指定了局域网内的某一台的ip地址,就是单播。这个地方其他大佬的博客里没有说明白。因此有很多人踩坑了。


服务端代码:

#include "pch.h"
#include <iostream>
#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

const int MAX_BUF_LEN = 255;
int main()
{
    WSADATA socketData;
	int err;

	err = WSAStartup(MAKEWORD(2, 2), &socketData);
	if (err != 0) {
		
		return -1;
	}

	if (LOBYTE(socketData.wHighVersion) != 2 || HIBYTE(socketData.wVersion) != 2) {
		WSACleanup();
		return -1;
	}

	// 使用AF_INET,是IPv4网络协议的套接字类型
	// SOCK_DGRAM 是UDP
	SOCKET serverSocket=socket(AF_INET,SOCK_DGRAM,0);

	// 打开广播
	bool bOpt = true;
	setsockopt(serverSocket, SOL_SOCKET, SO_BROADCAST, (char*)&bOpt, sizeof(bOpt));

	// 设置发送的地址
	SOCKADDR_IN serverAddr;
	memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	// 套接字地址为广播地址
	serverAddr.sin_addr.S_un.S_addr = htonl(INADDR_BROADCAST);  // 等价于serverAddr.sin_addr.S_un.S_addr = inet_addr("255.255.255.255");
	serverAddr.sin_port = htons(6789);

	
	char buf[MAX_BUF_LEN];
	memset(buf, 0, MAX_BUF_LEN);
	for (int i = 0; i < 2; i++) {
		sprintf_s(buf, "simplecloud94");
		// 向广播地址发送消息
		int sign=sendto(serverSocket, buf, strlen(buf),0,(SOCKADDR*)&serverAddr,sizeof(SOCKADDR_IN));
		if (sign == SOCKET_ERROR) {
			closesocket(serverSocket);
			WSACleanup();
			return -1;
		}
		printf("send: %s\n", buf);
		Sleep(5000);
	}

	closesocket(serverSocket);
	WSACleanup();
	return 0;


	if (serverSocket == INVALID_SOCKET) {
		closesocket(serverSocket);
		WSACleanup();
		return -1;
	}
    return 0;

}



UE4 客户端代码
创建一个c++的ue4 项目,在Build.cs结尾的文件
在这里插入图片描述
引入
在这里插入图片描述

基于Actor创建一个Actor的子类,命名为RamaUDPReceiver.h(网上所有的udp的代码,几乎都来自官网的一个大佬的代码)

RamaUDPReceiver.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Runtime/Networking/Public/Networking.h"
#include "GameFramework/Actor.h"
#include "RamaUDPReceiver.generated.h"

UCLASS()
class TESTUDP_API ARamaUDPReceiver : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ARamaUDPReceiver();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

public:

	FSocket* ListenSocket;
	
	FUdpSocketReceiver* UDPReceiver = nullptr;

	UFUNCTION(BlueprintCallable, Category = "UDP")
		void StartUDPReceiver(const FString& YourChosenSocketName, const FString& TheIP, const int32 ThePort, bool& success);
	UFUNCTION(BlueprintPure, Category = "UDP")
		void DataRecv(FString& str, bool& success);

	FORCEINLINE void ScreenMsg(const FString& Msg)
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, *Msg);
	}
	FORCEINLINE void ScreenMsg(const FString& Msg, const float Value)
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("%s %f"), *Msg, Value));
	}
	FORCEINLINE void ScreenMsg(const FString& Msg, const FString& Msg2)
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("%s %s"), *Msg, *Msg2));
	}

public:
	/** Called whenever this actor is being removed from a level */
	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
	
};

RamaUDPReceiver.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include "RamaUDPReceiver.h"


// Called when the game starts or when spawned
void ARamaUDPReceiver::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void ARamaUDPReceiver::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}
// Sets default values
ARamaUDPReceiver::ARamaUDPReceiver()
{
	// 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;
	//初始化ListenSocket
	ListenSocket = NULL;
}
//结束时出发事件
void ARamaUDPReceiver::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	Super::EndPlay(EndPlayReason);
	//UDPReceiver置空
	delete UDPReceiver;
	UDPReceiver = nullptr;

	//Clear all sockets!
	if (ListenSocket)
	{
		ListenSocket->Close();
		ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ListenSocket);
	}
}

//初始化Receiver
void ARamaUDPReceiver::StartUDPReceiver(const FString & YourChosenSocketName, const FString & TheIP, const int32 ThePort, bool & success)
{
	//TSharedRef<FInternetAddr> targetAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
	FIPv4Address Addr;
	FIPv4Address::Parse(TheIP, Addr);

	//使用指定的NetID和端口创建并初始化新的IPv4端点。
	// Any: Defines the wild card endpoint, which is 0.0.0.0:0
	FIPv4Endpoint Endpoint(FIPv4Address::Any, ThePort);  //所有ip地址本地
	//FUdpSocketBuilder: Implements a fluent builder for UDP sockets.
	ListenSocket = FUdpSocketBuilder(*YourChosenSocketName)
		.AsNonBlocking()//将套接字操作设置为非阻塞。 这个实例(用于方法链)。
		.AsReusable()//使绑定的地址可以被其他套接字重用。 这个实例(用于方法链)。
		.BoundToEndpoint(Endpoint)//设置将端口绑定到本地端点。 这个实例(用于方法链)。
		.WithReceiveBufferSize(2 * 1024 * 1024)//设置接收数据大小
		;
	//BUFFER SIZE
	int32 BufferSize = 2 * 1024 * 1024;
	ListenSocket->SetSendBufferSize(BufferSize, BufferSize);
	ListenSocket->SetReceiveBufferSize(BufferSize, BufferSize);

	if (ListenSocket)
	{
		ScreenMsg("The receiver is initialized");
		success = true;
	}
	else {
		ScreenMsg("No socket");
		success = false;
	}

	//return true;
}

void ARamaUDPReceiver::DataRecv(FString & str, bool & success)
{
	if (!ListenSocket)
	{
		ScreenMsg("No sender socket");
		success = false;
		
	}
	
	TSharedRef<FInternetAddr> targetAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
	TArray<uint8> ReceivedData;//定义一个接收器
	uint32 Size;
	//ListenSocket->HasPendingData(Size) 查询套接字以确定队列中是否有挂起的数据,如果套接字有数据,则为true,否则为false           Size参数指示单个recv调用的管道上有多少数据
	if (ListenSocket->HasPendingData(Size))
	{
		success = true;
		str = "";
		uint8 *Recv = new uint8[Size];
		int32 BytesRead = 0;

		//将数组调整到给定数量的元素。 新元素将被初始化。
		ReceivedData.SetNumUninitialized(FMath::Min(Size, 65507u));
		ListenSocket->RecvFrom(ReceivedData.GetData(), ReceivedData.Num(), BytesRead, *targetAddr);
		char ansiiData[1024];
		memcpy(ansiiData, ReceivedData.GetData(), BytesRead);//拷贝数据到接收器
		ansiiData[BytesRead] = 0;                            //判断数据结束
		FString debugData = ANSI_TO_TCHAR(ansiiData);         //字符串转换
		str = debugData;
		// memset(ansiiData,0,1024);//清空
	}
	else
	{
		success = false;
	}
}



在编辑器中创建一个基于RamaUDPReceiver的子类,命名为BP_UDPReceiver
在这里插入图片描述

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值