如何实现虚幻5的TCP通信

首先准备好一个服务端

这里作者采用的是使用Python编写一个简易的TCP服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import socket

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建服务端的socket对象
host = '127.0.0.1'
port = 4397

server.bind((host, port)) # 绑定

server.listen(5) # 监听

clientsocket,addr = server.accept()

# 保持执行直到接收到字符串exit
while True:
msg = clientsocket.recv(1024) #接收客户端的消息

strData = msg.decode("utf-8") # 解码

#判断客户端是否收到exit,是就退出此次对话
print("服务端收到:", strData)
if strData=='exit':
break

msg = input("回复:")
clientsocket.send(msg.encode("utf-8"))

server.close()

编写UE5端的TCP代码

以下代码会将接口暴露给蓝图,读者可根据需求使用C++或者蓝图调用消息发送和接受的接口。

.h文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#pragma once

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

UCLASS()
class TCPCLIENT_API AMyActor : public AActor
{
GENERATED_BODY()
public:
AMyActor();
protected:

// Called when the game starts or when spawned
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

public:

virtual void Tick(float DeltaTime) override;

FSocket* ListenerSocket;

FSocket* ConnectionSocket;

FIPv4Endpoint RemoteAddressForConnection;

FTimerHandle TCPSocketListenerTimerHandle;

FTimerHandle TCPConnectionListenerTimerHandle;

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文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include "MyActor.h"

// Sets default values
AMyActor::AMyActor()
{
// 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;
SocketClient = nullptr;
}


void AMyActor::BeginPlay()
{
Super::BeginPlay();
FString IPStr = "127.0.0.1";
int32 port = 4397;
bool success = SocketCreate(IPStr, port);
}

void AMyActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
UWorld* World = GetWorld();
GetWorld()->GetTimerManager().ClearTimer(TCPConnectionListenerTimerHandle);
GetWorld()->GetTimerManager().ClearTimer(TCPSocketListenerTimerHandle);
if (ConnectionSocket != NULL) {
ConnectionSocket->Close();
}

if (ListenerSocket != NULL) {
ListenerSocket->Close();
}

if (SocketClient) {
SocketClient->Close();
ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(SocketClient);
}

}

void AMyActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);


bool bReceive = false;
FString recvMessag = "";
SocketReceive(bReceive, recvMessag);

}

bool AMyActor::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 AMyActor::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 AMyActor::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 AMyActor::StringFromBinaryArray(TArray<uint8> BinaryArray)
{
return FString(ANSI_TO_TCHAR(reinterpret_cast<const char*>(BinaryArray.GetData())));
}

测试结果

image-20220904201728622

image-20220904201758389