江津集团网站建设,建平县网站建设,陕西西安网站建设公司,wordpress应用微信支付宝最近在使用UE的Socket模块与Python服务器进行通信时遇到了一些坑#xff0c;特此记录一下。
先来复现一下问题#xff0c;这里只截取关键代码。
UE端#xff1a;
bool ASoc::SendMsg(const FString Msg)
{TSharedRefFInternetAddr TargetAddr ISocketSubsy…最近在使用UE的Socket模块与Python服务器进行通信时遇到了一些坑特此记录一下。
先来复现一下问题这里只截取关键代码。
UE端
bool ASoc::SendMsg(const FString Msg)
{TSharedRefFInternetAddr 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端
def socrecv():global data,conn,addr,socwhile 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,recvthreadsocsocket.socket(socket.AF_INET,socket.SOCK_STREAM)soc.bind((ip,port))soc.listen(5)print(server listen...)bind Truewhile True:conn,addr soc.accept()print(addr,已接入)recvthread Thread(targetsocrecv)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函数的定义
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;elseresult result 4;}return result 1;
}没有去深究FString的中英文编码代码我是没看明白的使用这个算法计算数据的字节大小就能计算出正确的大小。
然后UE端的代码将int32 Size FCString::Strlen(SeriallizedChar) 1;换成int32 Size CalcUtf0NumFromString(SeriallizedChar);问题就解决了。