www.firnow.com时间:2007-11-28作者:佚名
编辑:本站 点击: [评论]
数据接收中粘包及半包的处理
2006-10-16 09:45
from http://www.acejoy.com/
ACE网络编程开发论坛
作者:Qinglan
在使用TCP协议的网络应用中,不可避免需要处理的一个问题就是半包和粘包的情况。
一种做法是在接收端设一个比较大的缓冲区,先将收到的数据包都放到缓冲区中,然后从该缓冲区中选取完整的数据包出来。该缓冲区的实现可以使用环形缓冲区进行优化,避免频繁的数据移动。使用该方法的一个描述见
http://www.vckbase.com/document/viewdoc/?id=1203
另外一种做法就是在接收的时候就只接收完整包。这要求数据包有固定的包头结构体,其中还要包含数据包的长度信息。在服务端接收的时候,先接收该包头数据,然后再接收指定长度的数据体。
在ACE中,用于保存消息的ACE_Message_Block有一个重要的特性:复合。即将多条消息连接在一起,形成一个单链表。这样便可以将先收到的包头和后收到的包体连成一个复合体,而不用建一个大的数据包,将两个Message_Block拷贝进去。
下面的示例采用ACE的Proactor框架完成,实现了服务器端半包及粘包的处理,以及ACE_Message_Block的复合,网络IO与逻辑处理的分离。
在Proactor框架中,接收新连接后,会初始化一个读请求,此时只要求读包头长度的数据:
void
init_read_stream()
{
ACE_NEW_NORETURN
(recv_data_, ACE_Message_Block (sizeof(PacketHeader),
MB_NORMAL_PACKET));
ACE_HANDLE handle =
this->handle
();
this->recv_data_->copy ((const char
*)&handle,
sizeof(ACE_HANDLE));
this->reader_.read
(*recv_data_, recv_data_->space
());
}
这里由于使用了网络IO与逻辑处理分线程处理的方式,递交给逻辑线程的数据包前面还加上了标识网络连接的handle,用以告诉逻辑线程该数据包是哪个客户端连接发上来的。
递交给逻辑线程的数据包头结构为:
struct PacketHeader
{
ACE_HANDLE
handler;
int data_length;
};
其中data_length就是从接收到的数据包中获取到的。
对于粘包的情况比较容易处理,先收了包头后再接收指定长度的数据包,多余的数据由下次再读取。
半包情况稍微复杂一点,每个数据包是分两次接收的,两次接收的时候都有可能接收不完全。
当接收包头不完全时所做的处理是继续提交读请求,读的数据长度为剩余的包头长度
if
(this->recv_data_->length() <
sizeof(PacketHeader))
{
//
数据包长度信息还未接收完
this->reader_.read
(*recv_data_, recv_data_->space
());
return;
}
当包头接收完后,新建一个Message_Block,长度为需要接收的数据体长度,并将该Message_Block链接到包头后
PacketHeader
* hdr = reinterpret_cast<PacketHeader *>
(this->recv_data_->rd_ptr());
ACE_Message_Block * data_mb =
this->recv_data_->cont();
if
(!data_mb)
{
//
刚刚接收完长度信息
ACE_NEW (data_mb,
ACE_Message_Block(hdr->data_length));
this->recv_data_->cont
(data_mb);
}
如果该数据包的包体接收完全,则将该完整的数据包发送到逻辑线程的消息队列,然后初始化一个新的接收请求
if
(data_mb->length () ==
hdr->data_length)
{
//
数据已接收完
//
再继续接收下一个数据包
logic_thread->putq
(recv_data_);
this->init_read_stream();
return;
}
否则表示数据体还未接收完全,处理方法也是继续提交剩余数据的读请求
this->reader_.read (*data_mb,
data_mb->space ());
直接该数据包读取完全。
数据包接收处理函数的完整实现为:
virtual void handle_read_stream (const
ACE_Asynch_Read_Stream::Result &result)
{
ACE_Message_Block
&mb = result.message_block ();
if (!result.success () ||
result.bytes_transferred () == 0)
{
mb.release
();
delete this;
}
else
{
if
(this->recv_data_->length() <
sizeof(PacketHeader))
{
//
数据包长度信息还未接收完
this->reader_.read (*recv_data_,
recv_data_->space ());
return;
}
PacketHeader * hdr = reinterpret_cast<PacketHeader *>
(this->recv_data_->rd_ptr());
ACE_Message_Block *
data_mb = this->recv_data_->cont();
if
(!data_mb)
{
// 刚刚接收完长度信息
ACE_NEW (data_mb, ACE_Message_Block(hdr->data_length));
this->recv_data_->cont (data_mb);
}
if (data_mb->length () ==
hdr->data_length)
{
//
数据已接收完
// 再继续接收下一个数据包
logic_thread->putq (recv_data_);
this->init_read_stream();
return;
}
// 否则继续接收该数据包
this->reader_.read
(*data_mb, data_mb->space ());
}
}
完整的服务器实现和模拟半包及粘包情况的客户端代码见
http://helloqinglan.googlepages.com/repack.rar
服务器仅实现了最简单的数据接收功能,为精减代码,未做错误检查
分享到:
相关推荐
netty案例,netty4.1基础入门篇八《NettyClient半包粘包处理、编码解码处理、收发数据方式》源码 ...
本篇文章将深入探讨如何在使用SuperSocket.ClientEngine.Core库时,处理客户端的粘包和半包问题。 粘包和半包是网络通信中的常见问题,主要出现在TCP协议中。由于TCP为了提高传输效率,会将多个小的数据包合并成一...
本实例是《Netty 粘包/半包原理与拆包实战》 一文的源代码工程。 大家好,我是作者尼恩。 在前面的文章中,完成了一个高性能的 Java 聊天程序,尼恩已经再一次的进行了通讯协议的选择。放弃了大家非常熟悉的json ...
netty案例,netty4.1基础入门篇九《自定义编码解码器,处理半包、粘包数据》源码 ...
然而,TCP在处理数据传输时,可能会出现“粘包”现象,这是开发者需要理解和解决的一个关键问题。 粘包是指在一个TCP连接中,发送方发送的多个数据包在接收方可能被合并成一个大的数据包进行接收,或者接收方可能将...
总的来说,处理iOS Socket编程中的粘包和半包问题,需要在数据格式设计时考虑到边界标识,并在接收数据时进行适当的解析和处理。通过定义固定的头部结构,结合长度字段,可以有效地识别和分离每个数据包,从而保证...
TCP 协议并不存在粘包和半包问题,但是由于 TCP 协议的设计,数据是以字节流的形式进行传输的,而“流”的传输是没有边界的,这就导致了粘包和半包问题的产生。要解决这个问题,需要在应用层面上实现消息边界的确定...
在IT行业中,网络编程是至关重要的一环,尤其是在高性能、高并发的应用场景下。...在实际项目中,理解如何处理半包和粘包问题,能够帮助我们更好地设计和实现网络协议,提升系统的稳定性和可靠性。
Java 中处理 Socket 通信过程中的粘包情况 在 Java 中处理 Socket 通信过程中,粘包情况是一个常见的问题。粘包情况是指在客户端和服务器端之间的数据传输过程中,多个数据包被合并成一个数据包发送,导致接收端...
处理Bytes粘包、半包、断包(ByteArrayDecoder),需配置自己的首尾标识符, 如果与首尾标识符相同的数据出现在首尾标识符以内的范围,建议将该数据进行转义, 如这样配置转义规则(假设首尾标识符是0x7e): 0x7e = 0x...
1. **半包粘包问题**:在网络通信中,由于TCP协议的流式传输特性,可能会出现数据包边界不清晰的问题,即“半包”或“粘包”。解决这个问题通常有两种方式:使用定长报文头或尾部的分隔符(如换行符)。定长报文头...
为了处理半包和粘包问题,我们需要自定义一套协议,比如在每个数据包前添加长度标识,这样接收端就能根据长度信息正确分割数据。 以下是一个简化的Socket图片传输流程: 1. **服务器端**: - 创建ServerSocket,...
该框架适用于微服务架构,能够处理高并发,并且具有低延迟的特性。 【描述】:“vertx3-tcp-samples”项目展示了如何使用Vert.x 3中的NetServer模块与TCP(传输控制协议)进行通信。TCP是一种面向连接的、可靠的...
如稳定性方面,连接池的释放,发送方面没有考虑只发送出半包的情况,优雅和非优雅关闭处理的问题,性能方面如内存池的选择,逻辑处理上TCP粘包处理,本组件完美的解决了这些问题,通过不同的参数配置,可适用于不同...
在网络传输过程中,可能会遇到**粘包**和**半包**的问题,即多个消息被错误地合并为一个消息发送或者一个消息被错误地分为了多个部分发送。 **Netty**通过以下方式解决这些问题: - **消息编码和解码**:为每条...
3. 编解码器:如何使用和编写自定义的编解码器处理粘包与半包问题。 4. 流量控制:理解TCP的滑动窗口机制及其在Netty中的应用。 5. Netty的内存管理:比如ByteBuf的使用和池化策略。 6. 高级特性:例如零拷贝技术、...
Netty是一款高性能的异步事件驱动的网络应用...这些知识点构成了Netty框架的核心,涵盖了从数据容器到事件处理,再到粘包半包问题处理的完整流程。了解和掌握这些知识点对于深入使用Netty进行网络编程具有重要的意义。
粘包和半包问题通常发生在TCP通信中,由于TCP为了提高传输效率,会将多次发送的数据合并成一个大的数据包进行传输,或者将一个大的数据包分割成多个小的数据包发送,这在处理结构化数据时可能会导致接收方无法正确...