【UE5】UE5与Python Socket通信中文数据接收不全

最近在使用UE的Socket模块与Python服务器进行通信时遇到了一些坑,特此记录一下。

先来复现一下问题,这里只截取关键代码。

UE端:

c++ 复制代码
bool ASoc::SendMsg(const FString& Msg)
{
	TSharedRef<FInternetAddr> TargetAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
	FString Serialized = Msg;
	bool bSend;
	TCHAR* SeriallizedChar = Serialized.GetCharArray().GetData();
	int32 Size = FCString::Strlen(SeriallizedChar) + 1;
	int32 Sent = 0;
	bSend = SocClient->SendTo((uint8*)TCHAR_TO_UTF8(SeriallizedChar),Size,Sent,*TargetAddr);
	if(bSend)
	{
		UE_LOG(LOGNLPFORUE,Log,TEXT("[To LTP | %d]: %s"),Size,*Msg);
	}
	else
	{
		UE_LOG(LOGNLPFORUE,Log,TEXT("Failed to send Msg to tlp"));
	}
	return bSend;
}

Python端:

python 复制代码
def socrecv():
    global data,conn,addr,soc
    while True:
        data = str(conn.recv(recvbuff),'utf-8','ignore')
        print('[recv msg from ue |',sys.getsizeof(data),']: ',repr(data))

def soclisten():
    global soc,bind,conn,addr,recvthread
    soc=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    soc.bind((ip,port))
    soc.listen(5)
    print('server listen...')
    bind = True
    while True:
        conn,addr = soc.accept()
        print(addr,'已接入')
        recvthread = Thread(target=socrecv)
        recvthread.setDaemon(True)
        recvthread.start()   

soclisten()

运行结果:

UE端发送的数据:

复制代码
LOGNLPFORUE: [To LTP | 45]: {"cmd":"ltp","type":"cws","data":"他叫汤姆去拿外衣"}
LOGNLPFORUE: [To LTP | 102]: {"cmd":"ltp","type":"cws","data":"He told Tom to get the coat, but Tom brought a piece of underwear"}

Python端接收到数据:

复制代码
[recv msg from ue | 148 ]:  '{"cmd":"ltp","type":"cws","data":"他叫汤'
[recv msg from ue | 151 ]:  '{"cmd":"ltp","type":"cws","data":"He told Tom to get the coat, but Tom brought a piece of underwear"}\x00'

可以看到数据容量并没有超出缓存上限,且Python端接收的数据都有做utf-8的编码转换,但依旧出现了中文数据接收不全,容量更大的英文数据反而没问题。

问题出在了UE端的FSocket::SendTo函数,SendTo函数的定义:

c++ 复制代码
bool FSocket::SendTo(const uint8* Data, int32 Count, int32& BytesSent, const FInternetAddr& Destination)

Data就是我们要发送的字节数据,Count数据的大小,BytesSent记录的是数据的发送进度,Destination是要发送数据的地址。

问题就出在Count的值上,可以看到在上面的代码中我们是直接计算的FString的长度,然后以这个长度作为发送的数据大小,在纯英文的数据中这没有任何问题,但在中文数据中,由于中文编码的特殊性,FString应该有做特殊的编码处理,导致直接计算FString的长度作为发送数据的字节大小其实是小于真实数据大小的,这就导致在UE端发送中文数据时就没有发送完整到数据,所以Python端接收到数据就出现数据不全的问题。

既然知道原因了,接下来就可以解决了。那么我们就需要去找一个计算FString中文数据真实字节数的算法来计算SenTo要发送字节数据大小。

在网上我也没找到相关的算法代码,于是就去请教了一位大佬,大佬给了我一份算法代码:

复制代码
int32 ASoc::CalcUtf0NumFromString(const FString& Str)
{
	int32 result = 0; 
	for (int i = 0; i < Str.Len(); i++)
	{
		if (Str[i] <= 0x7f)
			result = result + 1;
		else if (Str[i] > 0x7f && Str[i] <= 0x07ff)
			result = result + 2;
		else if (Str[i] > 0x07ff && Str[i] <= 0xffff)
			result = result + 3;
		else
			result = result + 4;
	}
	return result + 1;
}

没有去深究FString的中英文编码,代码我是没看明白的,使用这个算法计算数据的字节大小,就能计算出正确的大小。

然后UE端的代码将int32 Size = FCString::Strlen(SeriallizedChar) + 1;换成int32 Size = CalcUtf0NumFromString(SeriallizedChar);,问题就解决了。

相关推荐
山烛7 分钟前
KNN 算法中的各种距离:从原理到应用
人工智能·python·算法·机器学习·knn·k近邻算法·距离公式
guozhetao20 分钟前
【ST表、倍增】P7167 [eJOI 2020] Fountain (Day1)
java·c++·python·算法·leetcode·深度优先·图论
墨染点香26 分钟前
第七章 Pytorch构建模型详解【构建CIFAR10模型结构】
人工智能·pytorch·python
阿什么名字不会重复呢1 小时前
在线工具+网页平台来学习和操作Python与Excel相关技能
python·数据分析
Vertira1 小时前
python 阿里云 安装 dashscope的简介、安装
开发语言·python
gc_22992 小时前
学习Python中Selenium模块的基本用法(1:简介)
python·selenium
先做个垃圾出来………3 小时前
2116. 判断一个括号字符串是否有效
python
兮℡檬,3 小时前
房价预测|Pytorch
人工智能·pytorch·python
im_AMBER7 小时前
学习日志19 python
python·学习
mortimer10 小时前
安装NVIDIA Parakeet时,我遇到的两个Pip“小插曲”
python·github