UE4_UDPSocket进行不同工程的数据交互
来源:互联网 发布:网络语bug什么意思 编辑:程序博客网 时间:2024/05/21 06:00
以下内容仅对此次工程做解析。UE4.15.1 VS2015
实现效果:
客户端与服务器端的socket连接之后。客户端设定一个timer去发送消息服务端每个timer去检查是否接受到了消息,如果接收到了就讲消息打印
原理解析:
想要实现不同工程下的通讯。需要在同一个局域网内(外网还未测)。两个工程需要一个为客户端一个为服务端。在这里实现的是一个客户端发送数据而服务端接收数据。
实现步骤:
客户端:
1.创建一个socket:socket()。2.新建一个FInternetAddr共享变量并设置ip与端口号。3.socket发送到FInternetAddr指定ip端口号。
服务端:
1.创建一个socket:socket()。2.创建一个FInternetAddr共享变量并设置ip与端口号。
IPv4Endpoint Endpoint(FIPv4Address::Any, ThePort); //所有ip地址 本地的。any:0.0.0.0 任何主机ip都可用//FIPv4Endpoint Endpoint(Addr, ThePort); //指定ip地址
3.定义一个接收器,接收数据。并返回结果
具体实现:
客户端:
.h
#include "Runtime/Networking/Public/Networking.h"UCLASS()class SOCKET_ALL_API ARamaUDPSender : public AActor{ //新建isudp的bool变量 bool IsUDP; //新建函数RamaUDPSender_SendString(),用于发送消息 UFUNCTION(BlueprintCallable, Category = "UDP") bool RamaUDPSender_SendString(FString ToSend);public: //TSharedPtr是一个非侵入性引用计数的权威对象指针。 当可选模式模板参数设置为ThreadSafe时,此共享指针将有条件地线程安全。 //TSharedPtr(OtherType * InObject) 构造一个拥有指定对象的共享指针。 //新建RemoteAddr变量 TSharedPtr<FInternetAddr> RemoteAddr; //FSocket 特定套接字实现的抽象基类 //新建 SenderSocket指针变量 FSocket* SenderSocket; //新建StartUDPSender()函数,并传入socketname,ip,port与是否使用udp的变量 UFUNCTION(BlueprintCallable, Category = "UDP") bool StartUDPSender(const FString& YourChosenSocketName, const FString& TheIP, const int32 ThePort, bool UDP);public: //UPROPERTY 定义属性 //新建ShowOnScreenDebugMessages的bool变量。是否显示调试信息 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UDP") bool ShowOnScreenDebugMessages; //ScreenMsg // FORCEINLINE 它是非标准关键字,它覆盖编译器的启发式和强制内联当前函数。 FORCEINLINE void ScreenMsg(const FString& Msg) { if (!ShowOnScreenDebugMessages) return; GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, *Msg); } FORCEINLINE void ScreenMsg(const FString& Msg, const float Value) { if (!ShowOnScreenDebugMessages) return; GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("%s %f"), *Msg, Value)); } FORCEINLINE void ScreenMsg(const FString& Msg, const FString& Msg2) { if (!ShowOnScreenDebugMessages) return; 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;public: // Sets default values for this actor's properties ARamaUDPSender();}
.cpp
// Sets default valuesARamaUDPSender::ARamaUDPSender(){ // 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; //初始化变量 // SenderSocket 为 null ,默认显示调试信息 SenderSocket = NULL; ShowOnScreenDebugMessages = true;}//结束时调用函数void ARamaUDPSender::EndPlay(const EEndPlayReason::Type EndPlayReason){ Super::EndPlay(EndPlayReason); //~~~~~~~~~~~~~~~~ //结束之后,判断是否存在sendersocket,如果有,就把其关闭,并且销毁PLATFORM_SOCKETSUBSYSTE的这个sendersocket。 if (SenderSocket) //Clear all sockets! { SenderSocket->Close(); ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(SenderSocket); }}//开始发送初始化,传入socketname,ip与port和是否使用udp,默认使用。后面可以进行扩展bool ARamaUDPSender::StartUDPSender(const FString & YourChosenSocketName, const FString & TheIP, const int32 ThePort, bool UDP){ //FIPv4Endpoint Endpoint(FIPv4Address::Any, 6789); //Create Remote Address. //ISocketSubsystem::Get 获取给定的命名子系统的单例套接字子系统 //创建PLATFORM_SOCKETSUBSYSTEM的InternetAddr地址 RemoteAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); //创建bIsValid bool bIsValid; //FInternetAddr::SetIp void SetIp( const TCHAR * InAddr, bool & bIsValid ) 结果对bIsValid进行修改。 RemoteAddr->SetIp(*TheIP, bIsValid); RemoteAddr->SetPort(ThePort); if (!bIsValid) { ScreenMsg("Rama UDP Sender>> IP address was not valid!", TheIP); return false; } //FUdpSocketBuilder: Implements a fluent builder for UDP sockets. SenderSocket = FUdpSocketBuilder(*YourChosenSocketName) .AsReusable()//使绑定的地址可以被其他套接字重用。 这个实例(用于方法链)。 .WithBroadcast()/////////////广播 .WithSendBufferSize(2 * 1024 * 1024)//指定发送缓冲区的所需大小(以字节为单位)(0 = 默认值)。 //.BoundToEndpoint(Endpoint) ; //check(SenderSocket->GetSocketType() == SOCKTYPE_Datagram); //定义发送和接收的文件size范围 //Set Send Buffer Size int32 SendSize = 2 * 1024 * 1024; SenderSocket->SetSendBufferSize(SendSize, SendSize); SenderSocket->SetReceiveBufferSize(SendSize, SendSize); if (bIsValid) { bIsValid = true; } return bIsValid;}//发送消息bool ARamaUDPSender::RamaUDPSender_SendString(FString ToSend){ //判断是否存在SenderSocket。若没有直接不发送。返回false if (!SenderSocket) { ScreenMsg("No sender socket"); return false; } //~~~~~~~~~~~~~~~~ //发送消息 int32 BytesSent = 0; FString serialized = ToSend; TCHAR *serializedChar = serialized.GetCharArray().GetData(); int32 size = FCString::Strlen(serializedChar); int32 sent = 0; //SenderSocket->SendTo(Writer.GetData(), Writer.Num(), BytesSent, *RemoteAddr); //FSocket::SendTo virtual bool SendTo(const uint8 * Data,int32 Count,int32 & BytesSent,const FInternetAddr & Destination) // Data:需要发送的数据 Count:要发送数据长度 BytesSent:发送数据返回值,发送了多少 Destination:要发送的网络字节有序地址,在.h文件里面新建的ip地址变量,在StartUDPSender()中有赋值 SenderSocket->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); ScreenMsg(Str); return false; } ScreenMsg("UDP Send Succcess! INFO Sent = ", ToSend); return true;}
服务端:
.h
#include "Runtime/Networking/Public/Networking.h"public: // Called every frame virtual void Tick(float DeltaTime) override;public: //新建ListenSocket指针 //FSocket特定套接字实现的抽象基类 FSocket* ListenSocket; //新建空的UDPReceiver指针 //FUdpSocketReceiver 从UDP套接字异步接收数据。 FUdpSocketReceiver* UDPReceiver = nullptr; UFUNCTION(BlueprintCallable, Category = "UDP") //新建初始化Receiver函数 void StartUDPReceiver(const FString& YourChosenSocketName, const FString& TheIP, const int32 ThePort, bool& success); UFUNCTION(BlueprintPure, Category = "UDP") //DataRecv返回函数 void DataRecv(FString& str, bool& success); //ScreenMsg //FORCEINLINE 它是非标准关键字,它覆盖编译器的启发式和强制内联当前函数。 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;
.cpp
// Sets default valuesARamaUDPReceiver::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! // makes sure repeat plays in Editor dont hold on to old sockets! //若ListenSocket不为空 if (ListenSocket) { //关闭,销毁 ListenSocket->Close(); ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ListenSocket); }}//初始化Receivervoid ARamaUDPReceiver::StartUDPReceiver(const FString & YourChosenSocketName, const FString & TheIP, const int32 ThePort, bool & success){ //TSharedRef是不可空的非侵入性引用计数的权威对象引用。 //TSharedPtr(OtherType * InObject) 构造一个拥有指定对象的共享指针。 //新建RemoteAddr变量 //ISocketSubsystem::Get 获取给定的命名子系统的单例套接字子系统 // ISocketSubsystem::CreateInternetAddr TSharedRef < FInternetAddr > CreateInternetAddr ( uint32 Address, uint32 Port ) TSharedRef<FInternetAddr> targetAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); //FIPv4Address Implements an IPv4 address.,实现了ipv4地址 FIPv4Address Addr; //Parse() 将字符串转换为IPv4地址。 FIPv4Address::Parse(TheIP, Addr); //Create Socket // FIPv4Endpoint::FIPv4Endpoint FIPv4Endpoint ( const FIPv4Address & InAddress, uint16 InPort ) InAddress:The endpoint's IP address. InPort:The endpoint's port number. //使用指定的NetID和端口创建并初始化新的IPv4端点。 // Any: Defines the wild card endpoint, which is 0.0.0.0:0 FIPv4Endpoint Endpoint(FIPv4Address::Any, ThePort); //所有ip地址本地 //FIPv4Endpoint Endpoint(Addr, 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("No socket"); success = false; } if (ListenSocket) { ScreenMsg("The receiver is initialized"); success = true; } //return true;}void ARamaUDPReceiver::DataRecv(FString & str, bool & success){ if (!ListenSocket) { ScreenMsg("No sender socket"); success = false; //return success; } //TSharedRef是不可空的非侵入性引用计数的权威对象引用。 //TSharedPtr(OtherType * InObject) 构造一个拥有指定对象的共享指针。 //新建RemoteAddr变量 //ISocketSubsystem::Get 获取给定的命名子系统的单例套接字子系统 // ISocketSubsystem::CreateInternetAddr TSharedRef < FInternetAddr > CreateInternetAddr ( uint32 Address, uint32 Port ) 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; } //return success;}
调用:
客户端:
服务端:
阅读全文
0 0
- UE4_UDPSocket进行不同工程的数据交互
- Dialog中 不同Recycleview的数据交互
- struts2如何配置两个不同的action进行交互
- mybatis逆向工程进行不同条件查询的应用处理
- 使用pd 进行数据的反向工程
- 不同的sqlserver 实例之间的数据交互
- angualrjs的不同控制器里的数据共享和交互
- MFC中两个不同窗口之间的数据交互
- java不同对象之间的数据交互(通用)
- 远程调用 HttpInvoker JSP工程其间的数据交互
- 一个Maven工程中,不同的模块需要不同的JDK进行编译
- 一个Maven工程中,不同的模块需要不同的JDK进行编译
- JSON数据交互(SpringMVC进行json交互)
- SpringMVC进行json数据交互
- springmvc进行Json数据交互
- XMLHTTPRequest对象进行AJAX的异步数据交互
- jsonp实现应用的跨域请求进行数据交互
- 使用AngularJS的$http服务与服务端进行数据交互
- C++STL 常用 函数 用法
- centos7重新调整分区大小
- C++文件操作
- 总结7
- surfire 单元测试 使用了mock字节码再生和注入, UseSplitVerifier防止字节码校验
- UE4_UDPSocket进行不同工程的数据交互
- cannot change version of project facet Dynamic web module to 2.5
- Java 基础抽象类
- html网页布局
- [跳出语句]goto、break、return、continue的理解
- < 笔记 > Git
- MFC简单自学图形绘制1
- HDU 5572 An Easy Physics Problem (计算几何 点类 线类 向量类 线段与圆相交)
- 警告自己