TCP网络传输“粘包”问题,经典解决(附代码)

一、前言

关于TCP网络传输粘包,网上很多人写了原理。总结起来就一句话:这里拿Server和Client长连接,Server和Client之间通过信令传输做说明:

Server发送的时候按照一条条信令发送,到达操作系统网络层,首先进入缓冲池,然后TCP协议层从池子中获取数据,传输给Client。我们知道TCP的传输有几个方案,比如,滑动窗口、1比特方案。所以Client收到的数据已经不可能是一个个完整的信令的。

个人理解TCP粘包的概念:它描述了一个场景:“信令是一个个紧挨着的,好像是被粘在一起了”。在把信令拆开之前我们要做一个必须的任务:规整数据。规整了socket数据,那么原始二进制信令就出来了。

二、分析

刚才我讲过,Client从Socket收到的数据是不确定的,可能是1Byte,可能100Byte。而即便相同的信令,内容不一样长度也是不同的。将信令一个个摘出来,需要一个关键的属性:信令长度。通常信令的两个字节是长度,其表明了该条信令的长度。Client需要一个Buffer,用于规整信令。

通常Client接收Socket数据,存在以下几种场景:

(图1)

上图2展示了:信令前两个字节(橙色标注)是200B,然而Client的Buffer只是接收到了100B,那么客户端什么也不做,等待后续的socket数据

(图2)

上图2展示了:信令前两个字节(橙色标注)是50B,然而Client的Buffer已经超过50B了,那么Client可以截取50B,当成完整的信令,给后续逻辑处理了。

(图3)

上图3跟,图2相似。

三、逻辑实现

需要注意的是:在获取前两个字节的时候,需要判断系统是大端,还是小端

/**
 *	@brief	收到消息
 *
 *	@param 	data 	数据指针
 *	@param 	length 	数据长度
 */
void onReceiveData(NSData * data)
{
    if (data == NULL)
	{
        return;
    }
    [m_data appendData:data];
    const Byte *packageData = (Byte *)[m_data bytes];
    NSUInteger packageSize = [m_data length];

    // parse packet
    unsigned short messageSize = 0;
    NSUInteger pos = 0;
    while (pos < packageSize)
	{
        if (pos + 2 < packageSize)
		{ // can read message packet-size
            // read message packet-size
            messageSize = *((unsigned short *)(packageData + pos));
			// 现为小头
            //Byte tmp = (messageSize & 0xFF00) >> 8;
            //messageSize <<= 8;
            //messageSize |= tmp;

            if(messageSize <= packageSize - pos)
			{ // there is a complate message
                if (m_callback)
				{
                    m_callback->onDeliverMsg((packageData + pos), messageSize);
                }
                pos += messageSize;
                continue;
            }
        }
        break;
    }

    // deal with last bytes.
    if (pos < packageSize)
	{
        [m_data replaceBytesInRange:NSMakeRange(0, packageSize - pos) withBytes:(packageData + pos)];
        [m_data setLength:packageSize - pos];
    }
	else
	{
        [m_data setLength:0];
    }
}

(完)

时间: 2024-07-31 23:53:18

TCP网络传输“粘包”问题,经典解决(附代码)的相关文章

TCP 拆、粘包

Netty(三) 什么是 TCP 拆.粘包?如何解决? 前言 记得前段时间我们生产上的一个网关出现了故障. 这个网关逻辑非常简单,就是接收客户端的请求然后解析报文最后发送短信. 但这个请求并不是常见的 HTTP ,而是利用 Netty 自定义的协议. 有个前提是:网关是需要读取一段完整的报文才能进行后面的逻辑. 问题是有天突然发现网关解析报文出错,查看了客户端的发送日志也没发现问题,最后通过日志发现收到了许多不完整的报文,有些还多了. 于是想会不会是 TCP 拆.粘包带来的问题,最后利用 Net

有关TCP和UDP 粘包 消息保护边界

http://www.cnblogs.com/lancidie/archive/2013/10/28/3392428.html 在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的.因此TCP的socket编程,收发两端(客户端和服务器端)都要有一一成对的 socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一 个大的数据块,然后进行封包.这样,接收端,就难于分辨出来了,必须提供科学的拆包机

20 Apr 18 粘包问题及解决方法

20 Apr 18 一.上节课复习 1. TCP(建立的是一个双向连接)三次握手建连接,四次挥手断连接 三次握手:    c----syn=1 seq=x--->s    s----ack=1+x syn=1 seq=y--->c    c----ack=1+y------->s    四次挥手:    s------fin=1---------->c    c------>ack=1--------->s    c------>fin=1--------->

Netty系列(四)TCP拆包和粘包

Netty系列(四)TCP拆包和粘包 一.拆包和粘包问题 (1) 一个小的Socket Buffer问题 在基于流的传输里比如 TCP/IP,接收到的数据会先被存储到一个 socket 接收缓冲里.不幸的是,基于流的传输并不是一个数据包队列,而是一个字节队列.即使你发送了 2 个独立的数据包,操作系统也不会作为 2 个消息处理而仅仅是作为一连串的字节而言.因此这是不能保证你远程写入的数据就会准确地读取.举个例子,让我们假设操作系统的 TCP/TP 协议栈已经接收了 3 个数据包: 由于基于流传输

python之网络编程粘包

一.粘包 粘包现象 # 服务端 import socket import subprocess phone = socket.socket() phone.bind(('127.0.0.1',8888)) phone.listen(5) while 1: conn,addr = phone.accept() while 1: cmd = conn.recv(1024) ret = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=s

TCP网络通讯如何解决分包粘包问题(有模拟代码)

TCP作为常用的网络传输协议,数据流解析是网络应用开发人员永远绕不开的一个问题. TCP数据传输是以无边界的数据流传输形式,所谓无边界是指数据发送端发送的字节数,在数据接收端接受时并不一定等于发送的字节数,可能会出现粘包情况. 一.TCP粘包情况: 1. 发送端发送了数量比较的数据,接收端读取数据时候数据分批到达,造成一次发送多次读取:通常网络路由的缓存大小有关系,一个数据段大小超过缓存大小,那么就要拆包发送. 2. 发送端发送了几次数据,接收端一次性读取了所有数据,造成多次发送一次读取:通常是

网络编程 TCP协议:三次握手,四次回收,反馈机制 socket套接字通信 粘包问题与解决方法

TCP协议:三次握手,四次挥手 TCP协议建立双向通道. 三次握手, 建连接: 1:客户端向服务端发送建立连接的请求 2:服务端返回收到请求的信息给客户端,并且发送往客户端建立连接的请求 3:客户端接收到服务端发来的请求,返回接成功给服务端,完成双向连接 第一客戶向服务端发送请求,请求建立连接 服务端同客户端的请求,并同时向客户端发送建立 连接的请求,最后客户端同意后建立 双向连接. C ----> S C <---- S - 反馈机制: 客户端往服务端发送请求,服务端必须返回响应, 告诉客户

Socket编程实践(6) --TCP粘包原因与解决

流协议与粘包 粘包的表现 Host A 发送数据给 Host B; 而Host B 接收数据的方式不确定 粘包产生的原因 说明 TCP 字节流,无边界 对等方,一次读操作,不能保证完全把消息读完 UDP 数据报,有边界 对方接受数据包的个数是不确定的 产生粘包问题的原因分析 1.SQ_SNDBUF 套接字本身有缓冲区 (发送缓冲区.接受缓冲区) 2.tcp传送的端 mss大小限制 3.链路层也有MTU大小限制,如果数据包大于>MTU要在IP层进行分片,导致消息分割. 4.tcp的流量控制和拥塞控

Socket编程实践(5) --TCP粘包问题与解决

TCP粘包问题 因为TCP协议是基于字节流且无边界的传输协议, 因此非常有可能产生粘包问题, 问题描写叙述例如以下 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvempmMjgwNDQxNTg5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" /> 对于Host A 发送的M1与M2两个各10K的数据块, Host B 接收数据的方式不确定, 有以下