using UnrealBuildTool ; public class UE4_Network : ModuleRules public UE4_Network ( ReadOnlyTargetRules Target ) : base ( Target ) PCHUsage = PCHUsageMode . UseExplicitOrSharedPCHs ; PublicDependencyModuleNames . AddRange ( new string [] "Core" , "CoreUObject" , "Engine" , "InputCore" , "WebSockets" , "Json" PrivateDependencyModuleNames . AddRange ( new string [] { }); // Uncomment if you are using Slate UI // PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" }); // Uncomment if you are using online features // PrivateDependencyModuleNames.Add("OnlineSubsystem"); // To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true

3.2. 修改Server

在第2步中,使用send_time()发送的Json中Value为一串string,还可以发送其他类型的数据,例如string/bool/number/array等。在Python的服务类中,新增下面这个方法send_something,发送各种类型的数据(一个包bool/int/float/string的array)。发送的something字符串,包含Topic和Data,其中Data中又包好Key和Value。

# 发送各类型数据
    def send_something(self):
        self._add_cmd('Unreal','Something',[False,66,123.4,"str"])

改写main函数,发送一次time,再发送一次something

def main():
    s=MyServer('127.0.0.1',23333)
    s.start_server()
    s.send_time()
    s.send_something()

运行Server,运行Client,结果如下。各自收发成功,但UE4也只当这是个字符串,没有做任何解析。

3.3. 解析Json

在.h中新增一个解析的方法JsonParse(),在OnMessage事件中调用这个解析:

// .h
protected:
    //...
    void JsonParse(const FString InMessage);

在JsonParse()的实现中,先定义RootObj和JsonReader,用JsonReader反序列化这个FJsonObject类型的对象。获取Topic和Key,根据Key来判断做何解析。如果Key是Time,就认为Value的值的字符串;如果Key是Something,就认为Value的值是Array,而Array的每个元素又可以解析成不同类型的数据。

// .cpp
void AActorWebSocket::OnMessage(const FString& Message)
	UE_LOG(LogTemp,Warning,TEXT("%s Message:%s"),*FString(__FUNCTION__),*Message);
	JsonParse(Message);
void AActorWebSocket::JsonParse(const FString InMessage)
	TSharedPtr<FJsonObject> RootObj=MakeShareable(new FJsonObject());
	TSharedRef<TJsonReader<>> JsonReader=TJsonReaderFactory<>::Create(InMessage);
	if(FJsonSerializer::Deserialize(JsonReader,RootObj)) // 通过JsonReader读取RootObj
		FString Topic=RootObj->GetStringField("Topic"); // Topic
		UE_LOG(LogTemp,Warning,TEXT("%s Topic:%s"),*FString(__FUNCTION__),*Topic);
		TSharedPtr<FJsonObject> DataObj=MakeShareable(new FJsonObject());
		DataObj=RootObj->GetObjectField("Data"); // Data
		FString Key=DataObj->GetStringField("Key"); // Key
		UE_LOG(LogTemp,Warning,TEXT("%s Key:%s"),*FString(__FUNCTION__),*Key);
		if(Key.Equals("Time"))
			FString Time=DataObj->GetStringField("Value"); // Value type is String
			UE_LOG(LogTemp,Warning,TEXT("%s Time:%s"),*FString(__FUNCTION__),*Time);
		else if(Key.Equals("Something"))
			TArray<TSharedPtr<FJsonValue>> Value=DataObj->GetArrayField("Value"); // Value type is Array
			bool BoolValue=Value[0]->AsBool();
			int IntValue=Value[1]->AsNumber();
			float FloatValue=Value[2]->AsNumber();
			FString StringValue=Value[3]->AsString();
			UE_LOG(LogTemp,Warning,TEXT("%s BoolValue:%d"),*FString(__FUNCTION__),BoolValue);
			UE_LOG(LogTemp,Warning,TEXT("%s IntValue:%d"),*FString(__FUNCTION__),IntValue);
			UE_LOG(LogTemp,Warning,TEXT("%s FloatValue:%f"),*FString(__FUNCTION__),FloatValue);
			UE_LOG(LogTemp,Warning,TEXT("%s StringValue:%s"),*FString(__FUNCTION__),*StringValue);

测试结果如下,UE4已经能分别解析Json中各类型的数据了。

3.4. 写入Json

现在UE4能接收到消息,并且作为Json来解析了。下面记录如何序列化写入Json,并发送出去给Server,让Server能够解析。

修改MySend(),初始化一个TSharedPtr<FJsonObject>类型的RootObj,给他新增几个字段。其中IsExecute字段的值是bool,Type字段的值是String,Value字段的值是JsonValue类型

void AActorWebSocket::MySend()
	TSharedPtr<FJsonObject> RootObj=MakeShareable(new FJsonObject);
	RootObj->SetBoolField("IsExecute",true);
	RootObj->SetStringField("Type","Test");
	TSharedPtr<FJsonValue> Value=MakeShareable(new FJsonValueNumber(GetGameTimeSinceCreation()));
	RootObj->SetField("Value",Value);
	FString JsonStr;
	TSharedRef<TJsonWriter<TCHAR>> JsonWriter=TJsonWriterFactory<TCHAR>::Create(&JsonStr);
	FJsonSerializer::Serialize(RootObj.ToSharedRef(),JsonWriter);
	if(Socket->IsConnected())
		// Socket->Send(FString::SanitizeFloat(GetGameTimeSinceCreation()));
		Socket->Send(JsonStr);
	UE_LOG(LogTemp,Warning,TEXT("%s Result:%s"),*FString(__FUNCTION__),*JsonStr);

修改PythonWebSocketServer中的接收方法,简单解析收到的消息:

# 接收处理
    async def __consumer(self,message):
        print('recv message: {0}'.format(message))
        self.__isExecute=True