UE4_UDPSocket进行不同工程的数据交互
2017-10-19 21:21
435 查看
以下内容仅对此次工程做解析。UE4.15.1 VS2015
实现效果:
原理解析:
实现步骤:
客户端:
服务端:
.h
.cpp
服务端:
.h
.cpp
服务端:
实现效果:
客户端与服务器端的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 values ARamaUDPSender::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; 4000 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 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! // makes sure repeat plays in Editor dont hold on to old sockets! //若ListenSocket不为空 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是不可空的非侵入性引用计数的权威对象引用。 //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; }
调用:
客户端:服务端:
相关文章推荐
- Socket 进行UDP广播数据(GCDAsyncUdpSocket)
- 局域网内通过UDP协议进行传输接受数据——AsyncUdpSocket
- Socket 进行UDP广播数据(GCDAsyncUdpSocket)
- 关于如何在MFC工程中输入不同的数据进行调试
- Android使用Socket(Tcp/Udp)协议进行数据传输(传输大文件)
- linux 多次创建不同的UDP socket进行通信,最终通信用的UDP 源端口以最后一次创建的socket使用的源端口为准
- UE4_TCPSocket进行不同设备之间的通信
- 使用pd 进行数据的反向工程
- 使用Json数据进行服务器与android端交互
- Flex数据交互方法 :httpservice, webservice, RemoteObject, socket
- socket编程——TCP/UDP数据传输
- 利用R语言进行交互数据可视化
- PBOC/EMV-交易流程详解--POS与卡片的数据交互进行分析
- Java、C#端进行Socket异步数据传输
- 11-socket的实践到内核--UDP的socket数据的发送
- JAVA Socket编程学习7--NIO同时接收TCP和UDP数据
- android中不同app间数据交互(1、简单一次性数据交互)
- Ionic从零单排(五)——Ionic程序与Java后台进行数据交互
- Ext4核心组件Grid的变化及学习(4):grid与服务端使用direct进行数据交互
- udp的socket数据传输