以下内容仅对此次工程做解析。UE4.15.1 VS2015
socket:服务器端与客户端是一对一关系。
实现效果:
通过按钮事件触发创建socket
服务器端的socket先建立,然后才能等待客户端的socket接入
客户端与服务器端的socket连接之后。
服务器端/客户端
设定一个timer去遍历是否接收到数据,
设定一个按钮事件去触发发送数据到客户端/客户端
原理解析:
想要实现不同工程下的通讯。需要在同一个局域网内(外网还未测)。两个工程需要一个为客户端一个为服务端。在这里实现的是一个客户端发送数据而服务端接收数据。
实现步骤:
客户端:
1.创建socket: socket();
2.连接socket: connect();
3.设置timer去扫描是否收到来自服务端的信息:receive();
4.自定义按钮事件触发发送事件:sendto();
服务端:
1.创建socket:socket();
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添加事件
在蓝图中调用