UE4_TCPSocket进行不同设备之间的通信

以下内容仅对此次工程做解析。UE4.15.1 VS2015
socket:服务器端与客户端是一对一关系。

实现效果:

通过按钮事件触发创建socket
服务器端的socket先建立,然后才能等待客户端的socket接入
客户端与服务器端的socket连接之后。
服务器端/客户端   
     设定一个timer去遍历是否接收到数据,
     设定一个按钮事件去触发发送数据到客户端/客户端

原理解析:

想要实现不同工程下的通讯。需要在同一个局域网内(外网还未测)。两个工程需要一个为客户端一个为服务端。在这里实现的是一个客户端发送数据而服务端接收数据。

实现步骤:

客户端:
1.创建socket: socket();
2.连接socket: connect();
3.设置timer去扫描是否收到来自服务端的信息:receive();
4.自定义按钮事件触发发送事件:sendto();
服务端:
1.创建socketsocket();
2.绑定一个ip和端口: bind();---在这里使用0.0.0.0 作为ip,意为选择当前主机ip作为绑定ip,这样可移植性更高。只需要更改客户端发送的ip地址即可

这里写图片描述

bool ATCPSocketServer::bindSoc(const FString & TheIP, const int32 ThePort)
{
       FIPv4Address::Parse(TheIP, ip);
       TSharedRef<FInternetAddr> addr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
       addr->SetIp(ip.Value);
       addr->SetPort(ThePort);
       bool bBind = SocketServer->Bind(*addr);
       return bBind;
}
3.启动监听:listen();
4.接受客户端连接:accept();
注意:到这一步之后才可以接受客户端的接入。所以。想要创建服务器端的socket,前面的步骤都需要正确执行。
5.启用timer进行扫描是否有来之客户端的信息:recerve();
6.启用自定义按钮事件进行发送设置:sendto();

具体实现:
首先,需要在[ build.cs ] 文件中添加 “Sockets”,”Networking”

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" ,//添加后面两个
                                                                                 "Sockets","Networking"});

客户端:
.h文件

#include "Runtime/Networking/Public/Networking.h"
UCLASS()
class TCPCLIENT_API ATCPSocketClient : public AActor
{
public:
       // Sets default values for this actor's properties
       ATCPSocketClient();
public:
       /** Called whenever this actor is being removed from a level */
       virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

       UFUNCTION(BlueprintCallable, Category = "MySocket")
              bool SocketCreate(FString IPStr, int32 port);

       UFUNCTION(BlueprintCallable, Category = "MySocket")
              void SocketSend(FString meesage);

       UFUNCTION(BlueprintPure, Category = "MySocket")
              void SocketReceive(bool& bReceive, FString& recvMessage);

       FString StringFromBinaryArray(TArray<uint8> BinaryArray);

       FSocket *SocketClient;

       FIPv4Address ip;

}

.cpp文件

// Sets default values
ATCPSocketClient::ATCPSocketClient()
{
       SocketClient = NULL;
}

void ATCPSocketClient::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
       Super::EndPlay(EndPlayReason);
       if (SocketClient)
       {
              //关闭,销毁
              SocketClient->Close();
              ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(SocketClient);
       }
}

bool ATCPSocketClient::SocketCreate(FString IPStr, int32 port)
{
       FIPv4Address::Parse(IPStr, ip);

       TSharedRef<FInternetAddr> addr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
       addr->SetIp(ip.Value);
       addr->SetPort(port);

       SocketClient = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateSocket(NAME_Stream, TEXT("default"), false);

       if (SocketClient->Connect(*addr))
       {
              GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, TEXT("Connect Succ!"));
              UE_LOG(LogTemp, Warning, TEXT("Connect Succ!"));
              return true;
       }
       else
       {
              GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, TEXT("Connect failed!"));
              UE_LOG(LogTemp, Warning, TEXT("Connect failed!"));
              return false;
       }
}

void ATCPSocketClient::SocketSend(FString meesage)
{
       TCHAR *seriallizedChar = meesage.GetCharArray().GetData();
       int32 size = FCString::Strlen(seriallizedChar) + 1;
       int32 sent = 0;

       if (SocketClient->Send((uint8*)TCHAR_TO_UTF8(seriallizedChar), size, sent))
       {
              GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, TEXT("_____Send Succ!"));
              UE_LOG(LogTemp, Warning, TEXT("_____Send Succ!"));
       }
       else
       {
              GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, TEXT("_____Send failed!"));
              UE_LOG(LogTemp, Warning, TEXT("_____Send failed!"));
       }
}

void ATCPSocketClient::SocketReceive(bool & bReceive, FString & recvMessage)
{
       recvMessage = "";
       bReceive = false;
       if (!SocketClient)
       {
              return;
       }

       TArray<uint8> ReceiveData;
       uint32 size;
       uint8 element = 0;
       while (SocketClient->HasPendingData(size))
       {
              ReceiveData.Init(element, FMath::Min(size, 65507u));

              int32 read = 0;
              SocketClient->Recv(ReceiveData.GetData(), ReceiveData.Num(), read);

       }

       if (ReceiveData.Num() <= 0)
       {
              return;
       }
       FString log = "Total Data read! num: " + FString::FromInt(ReceiveData.Num() <= 0);

       GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, log);
       UE_LOG(LogTemp, Warning, TEXT("Recv log:   %s"), *log);

       const FString ReceivedUE4String = StringFromBinaryArray(ReceiveData);

       log = "Server:" + ReceivedUE4String;
       GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, log);
       UE_LOG(LogTemp, Warning, TEXT("*** %s"), *log);

       recvMessage = ReceivedUE4String;

       bReceive = true;
}

FString ATCPSocketClient::StringFromBinaryArray(TArray<uint8> BinaryArray)
{
       return FString(ANSI_TO_TCHAR(reinterpret_cast<const char*>(BinaryArray.GetData())));
}

服务端:

.h文件

#include "Runtime/Networking/Public/Networking.h"
UCLASS()
class TCPSERVER_API ATCPSocketServer : public AActor
{
public:
       // Sets default values for this actor's properties
       ATCPSocketServer();
public:
       /** Called whenever this actor is being removed from a level */
       virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

       UFUNCTION(BlueprintCallable, Category = "MySocket")
              bool createSoc();
       UFUNCTION(BlueprintCallable, Category = "MySocket")
              bool bindSoc(const FString& TheIP, const int32 ThePort);
       UFUNCTION(BlueprintCallable, Category = "MySocket")
              bool listenSoc(const int32 MaxBacklog);
       UFUNCTION(BlueprintCallable, Category = "MySocket")
              bool acceptSoc(const FString& TheIP, const int32 ThePort);
       UFUNCTION(BlueprintCallable, Category = "MySocket")
              bool sendSoc(const FString& sendMessage);
       UFUNCTION(BlueprintCallable, Category = "MySocket")
              void recvSoc();
       FString StringFromBinaryArray(const TArray<uint8>& BinaryArray);
       FSocket* SocketServer;
       FSocket* SocketClient;
       FIPv4Address ip;
}

.cpp文件

// Sets default values
ATCPSocketServer::ATCPSocketServer()
{
       //初始化
       SocketServer = NULL;
       SocketClient = NULL;
}

void ATCPSocketServer::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
       Super::EndPlay(EndPlayReason);
       if (SocketServer)
       {
              //关闭,销毁
              SocketServer->Close();
              ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(SocketServer);
       }
       if (SocketClient)
       {
              //关闭,销毁
              SocketClient->Close();
              ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(SocketClient);
       }
}

bool ATCPSocketServer::createSoc()
{
       SocketServer = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateSocket(NAME_Stream, TEXT("default"), false);

       if (!SocketServer){
              return false;
       }
       // SocketServer.SetNonBlocking(false);
       //SocketServer->SetNonBlocking(false);
       return true;
}

bool ATCPSocketServer::bindSoc(const FString & TheIP, const int32 ThePort)
{
       FIPv4Address::Parse(TheIP, ip);
       TSharedRef<FInternetAddr> addr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
       addr->SetIp(ip.Value);
       addr->SetPort(ThePort);
       bool bBind = SocketServer->Bind(*addr);
       return bBind;
}

bool ATCPSocketServer::listenSoc(const int32 MaxBacklog)
{
       bool bListen = SocketServer->Listen(MaxBacklog);
       return bListen;
}

bool ATCPSocketServer::acceptSoc(const FString & TheIP, const int32 ThePort)
{
       TSharedRef<FInternetAddr> targetAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
       FIPv4Address::Parse(TheIP, ip);
       targetAddr->SetIp(ip.Value);
       targetAddr->SetPort(ThePort);
       SocketClient = SocketServer->Accept(*targetAddr, "aaa");
       if (!SocketClient)
              return false;
       return true;
}

bool ATCPSocketServer::sendSoc(const FString & sendMessage)
{
       TSharedRef<FInternetAddr> targetAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
       //FIPv4Address::Parse(TheIP, ip);
       //targetAddr->SetIp(ip.Value);
       //targetAddr->SetPort(ThePort);

       FString serialized = sendMessage;

       bool bsend;
       TCHAR *seriallizedChar = serialized.GetCharArray().GetData();
       int32 size = FCString::Strlen(seriallizedChar) + 1;
       int32 sent = 0;
       //注意,要用客户端这个socket
       bsend = SocketClient->SendTo((uint8*)TCHAR_TO_UTF8(seriallizedChar), size, sent, *targetAddr);

       if (bsend)
       {
              GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, TEXT("_____Send Succ!"));
              UE_LOG(LogTemp, Warning, TEXT("_____Send Succ!"));
       }
       else
       {
              GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, TEXT("_____Send failed!"));
              UE_LOG(LogTemp, Warning, TEXT("_____Send failed!"));
       }
       return bsend;
}

void ATCPSocketServer::recvSoc()
{
       TSharedRef<FInternetAddr> targetAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
       TArray<uint8> ReceivedData;//定义一个接收器
       uint32 Size;
       //注意,要用客户端这个socket
       if (SocketClient->HasPendingData(Size))
       {
              uint8 *Recv = new uint8[Size];
              int32 BytesRead = 0;
              //将数组调整到给定数量的元素。 新元素将被初始化。
              ReceivedData.SetNumUninitialized(FMath::Min(Size, 65507u));
              //注意,要用客户端这个socket
              SocketClient->RecvFrom(ReceivedData.GetData(), ReceivedData.Num(), BytesRead, *targetAddr);
              if (ReceivedData.Num() > 0)
              {
                     //打印
                     GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Data Bytes Read ~> %d"), ReceivedData.Num()));
                     FString ReceivedUE4String = StringFromBinaryArray(ReceivedData);
                     GEngine->AddOnScreenDebugMessage(-1, 0.5f, FColor::Red, FString::Printf(TEXT("As String Data ~> %s"), *ReceivedUE4String));
                     //判断是否发送了相对的指令,进行对应事件调用
                     if (ReceivedUE4String.Equals("jiegege"))
                     {
                           sendSoc("server auto send ");
                     }



              }
       }
}

FString ATCPSocketServer::StringFromBinaryArray(const TArray<uint8>& BinaryArray)
{
       return FString(ANSI_TO_TCHAR(reinterpret_cast<const char*>(BinaryArray.GetData())));
}

调用:

客户端:
在project setting中添加事件
这里写图片描述
蓝图调用
这里写图片描述
这里写图片描述

服务端:
在projectsetting添加事件
这里写图片描述
在蓝图中调用
这里写图片描述
这里写图片描述
这里写图片描述

  • 11
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 22
    评论
UE4_API_Reference 是一个非常宝贵的资源,它提供了 Unreal Engine 4 引擎的全部 API 详细文档。这些离线文档对开发者来说非常重要,因为它们可以在没有网络连接的情况下提供对 UE4 引擎的完整了解和查询支持。 UE4_API_Reference 全部离线文档包括了对 UE4 的各个模块、类、函数和属性的详细描述和用法示例。开发者可以通过这些文档深入了解各个功能模块的实现原理以及如何正确使用它们。这对于开发者学习 UE4 引擎以及进行游戏开发非常有帮助。 离线文档的好处在于可以在没有网络的环境中使用。开发者不需要依赖互联网来查找关于 UE4 API 的信息,而是可以直接在本地进行搜索和查询。这不仅提高了开发效率,还可以避免由于网络问题导致的信息获取困难。 UE4_API_Reference 全部离线文档的编制工作需要花费大量的时间和精力。文档中的每一个类、函数和属性都需要进行详细描述和示例演示,以便开发者能够更好地理解和使用。这就要求文档编写人员具备广泛的知识和丰富的经验,以确保文档的完整性和准确性。 总之,UE4_API_Reference 全部离线文档对于 UE4 开发者来说是一个非常宝贵的资源。它提供了对 UE4 引擎的全面了解和查询支持,可以帮助开发者更好地学习和使用 UE4 引擎进行游戏开发。同时,它也方便了开发者在没有网络连接的环境中进行开发工作,提高了开发效率。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值