网络发送频率和网络堵塞,就可能出现粘包情况。
1 发送端需要等发送缓冲区满才发送出去,造成粘包
2 接收方不及时接收缓冲区的包,造成多个包接收
如图(盗取的)
处理逻辑:
声明一个读取到数据的数据缓存变量,从收到第一个数据包开始步骤:
1.读出来的数据依次存放到该数据缓存变量,然后判断处理该数据缓存变量的内容:
2.只处理内容数据长度大于等于当前包体大小的情况(其他情况跳过继续步骤1),然后把该等于包体数据拿出来存放分发,剩余内容数据拷贝到数据缓存前面(拿出的数据,后面剩余继续补上,如缓存123456789,拿出来的12345,剩下放到前面如6789XXXXX)。然后继续步骤1,循环读取处理。
UE4具体代码描述实现如下:
MessageBase.h:
#define MESSAGE_MAX_LENGTH 10240
class FMessageBase//消息结构,后面自定义消息结构继承该类
{
public:
FMessageBase():HeadKey(0)
{
Length = sizeof(this);
}
~FMessageBase()
{}
int32 Length;//包体大小,消息长度
};
struct RecvBufferData
{
RecvBufferData()
:index(0)
{
Bufferdata = (uint8*)malloc(MESSAGE_MAX_LENGTH * 10);
}
~RecvBufferData()
{
free(Bufferdata);
}
bool ReadBufferData(FSocket* Socket);//从Socket->Recv读取数据
template
T* GetMessage();//针对数据缓存区处理,拿到所需包的数据,剩余的数据继续放到Bufferdata最前面地址开始
int OffsetIndex;//记录Bufferdata的最终数据位置偏移,换句话就是缓存数据大小
uint8* Bufferdata;//读取消息数据缓存区,最后对这个判断处理。
};
MessageBase.cpp:
bool RecvBufferData::ReadBufferData(FSocket* Socket)
{
int32 BytesRead = 0;//实际这次所能读到的数据量
bool RecvRet = Socket->Recv(Bufferdata + OffsetIndex, MESSAGE_MAX_LENGTH, BytesRead);
if(RecvRet)
{
OffsetIndex += BytesRead;//记录当前数据位置偏移
}
return RecvRet;
}
template
T* RecvBufferData::GetMessage()
{
auto package_size = sizeof(FMessageBase);
if (OffsetIndex < package_size)//小于包体跳过返回不处理
return nullptr;
FMessageBase * package = reinterpret_cast
if (OffsetIndex < package->Length)//小于包体跳过返回不处理
return nullptr;
T* Ret = (T*)malloc(package->Length);//声明包大小的消息结构来存放数据
memcpy(Ret, Bufferdata, package->Length);//从Bufferdata拿出等于package->Length的数据放到Ret
OffsetIndex = OffsetIndex - package->Length;//由于Bufferdata拿了package->Length数据,计算剩余数据大小
///memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,但复制后源内容会被更改
//把Bufferdata拿出的数据后,剩余数据起始地址Bufferdata + package->Length,然后把剩余数据拷贝到Bufferdata最前面来,
//为后面读取到数据继续可以依次放到Bufferdata后面
memmove(Bufferdata, Bufferdata + package->Length, OffsetIndex);
return Ret;//返回当前取到的数据包
}
NetActor.h:
class HIGHSPEEDNETDRIVER_API ANetActor: public AActor
{
public:
RecvBufferData* ClientRecvBufferData;
virtual void Tick( float DeltaSeconds ) override;
virtual void BeginPlay() override;
virtual void Destroyed();
FSocket* ClientSocket;/
virtual bool ReceiveData();
virtual bool InitClient();
}
NetActor.cpp:
ANetActor::ANetActor(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
ClientRecvBufferData = new RecvBufferData();
}
void ANetActor::BeginPlay()
{
Super::BeginPlay();
InitClient();
}
bool ANetActor::InitClient()
{
if (GetNetMode() == NM_ClientServerPort!=0 && ServerIP != 0)
{
FString ServerIPAddr = "";
UNetDriver* Driver = GetWorld()->GetNetDriver();
if ( Driver&&Driver->ServerConnection)
{
Driver->ServerConnection->GetAddrAsInt(),
*(Driver->ServerConnection->LowLevelDescribe()),
*(Driver->ServerConnection->LowLevelGetRemoteAddress()));
{
ServerIPAddr = Driver->ServerConnection->LowLevelGetRemoteAddress();
}
}
FSocket* Socket = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateSocket(NAME_Stream, TEXT("default"), false);
if (!Socket)
{
return false;
}
TSharedRef
if (!ServerIPAddr.IsEmpty())
{
InternetAddr->SetIp(*ServerIPAddr, bValid);
}
else
{
InternetAddr->SetIp(ServerIP);
}
InternetAddr->SetPort(ServerPort);
int32 ReceiveBufferSize = 2 * 1024 * 1024;
int32 SendBufferSize = 2 * 1024 * 1024;
int32 NewSize = 0;
Socket->SetReceiveBufferSize(ReceiveBufferSize, NewSize);
Socket->SetSendBufferSize(SendBufferSize, NewSize);
bool Connected = Socket->Connect(*InternetAddr);
if (!Connected)
{
if (Socket)
{
Socket->Close();
ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(Socket);
}
return false;
}
if (ClientSocket)
{
ClientSocket->Close();
ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ClientSocket);
}
ClientSocket = Socket;
bClientIsReady = true;
}
return bClientIsReady;
}
void ANetActor::Destroyed()
{
Super::Destroyed();
if (nullptr != ClientRecvBufferData)
{
delete ClientRecvBufferData;
ClientRecvBufferData = nullptr;
}
}
void ANetActor::Tick( float DeltaTime )
{
Super::Tick( DeltaTime );
if (GetNetMode() == NM_Client)
ReceiveData();
}
bool ANetActor::ReceiveData()
{
if (ClientSocket)
{
uint32 DatagramSize = 0;
if(ClientSocket->HasPendingData(DatagramSize))
{
if (ClientRecvBufferData->ReadBufferData(ClientSocket))//开始读取数据到数据缓存
{
#if PLATFORM_WINDOWS && !WITH_EDITOR
// canot dump my game!!!
//__try//try
try
{
#endif
FMessageBase* Message = ClientRecvBufferData->GetMessage
while (Message)
{
ReceiveMessage(Message);//消息分发应用层
free(Message);//对应T* Ret = (T*)malloc(package->Length);//声明包大小的消息结构来存放数据,释放
Message = ClientRecvBufferData->GetMessage
}
#if PLATFORM_WINDOWS && !WITH_EDITOR
}
//__except (EXCEPTION_EXECUTE_HANDLER)//catch (std::exception& e)
catch(std::exception& e)
{
printf("%s", e.what());
BufferMessage.Remove(ClientSocket);
}
#endif
}
}
}
return true;
}