tcp粘包 java_详说tcp粘包和半包

article/2025/10/13 16:39:59

tcp服务端和客户端建立连接后会长时间维持这个连接,用于互相传递数据,tcp是以流的方式传输数据的,就像一个水管里的水一样,从一头不断的流向另一头。

理想情况下,发送的数据包都是独立的,

9cc0c6f33922be1ddbba77e55d3be40e.png

现实要复杂一些,发送方和接收方都有各自的缓冲区。

发送缓冲区:应用不断的把数据发送到缓冲区,系统不断的从缓冲区取数据发送到接收端。

接收缓冲区:系统把接收到的数据放入缓冲区,应用不断的从缓冲区获取数据。

当发送方快速的发送多个数据包时,每个数据包都小于缓冲区,tcp会将多次写入的数据放入缓冲区,一次发送出去,服务器在接收到数据流无法区分哪部分数据包独立的,这样产生了粘包。

66a4ac19ff62dcaa0d6df261b2b4285d.png

或者接收方因为各种原因没有从缓冲区里读取数据,缓冲区的数据会积压,等再取出数据时,也是无法区分哪部分数据包独立的,一样会产生粘包。

发送方的数据包大于缓存区了,其中有一部分数据会在下一次发送,接收端一次接收到时的数据不是完整的数据,就会出现半包的情况。

a38ab34101ca8e9f502687dabeff4756.png

我们可以还原一下粘包和半包,写一个测试代码

服务端

func main() {

l, err := net.Listen("tcp", ":8899")

if err != nil {

panic(err)

}

fmt.Println("listen to 8899")

for {

conn, err := l.Accept()

if err != nil {

panic(err)

} else {

go handleConn(conn)

}

}

}

func handleConn(conn net.Conn) {

defer conn.Close()

var buf [1024]byte

for {

n, err := conn.Read(buf[:])

if err != nil {

break

} else {

fmt.Printf("recv: %s \n", string(buf[0:n]))

}

}

}

客户端

func main() {

data := []byte("~测试数据:一二三四五~")

conn, err := net.Dial("tcp", ":8899")

if err != nil {

panic(err)

}

for i := 0; i < 2000; i++ {

if _, err = conn.Write(data); err != nil {

fmt.Printf("write failed , err : %v\n", err)

break

}

}

}

查看一下输出

recv: ~测试数据:一二三四五~

recv: ~测试数据:一二三四五~ ~测试数据:一二三四五~

recv: ~测试数据:一�

recv: ��三四五~ ~测试数据:一二三四五~

recv: ~测试数据:一二三四五~

recv: ~测试数据:一二三四五~ ~测试数据:一二三四五~ ~测试数据:一二三四五~ ~测试数据:一二三四五~

recv: ~测试数据:一二三四五~

正常情况下输出是recv: ~测试数据:一二三四五~,发生粘包的时候会输出多个数据包,当有半包的情况下输出的是乱码数据,再下一次会把剩下的半包数据也输出。

要解决也简单的就想办法确定数据的边界,常见的处理方式:

固定长度: 比如规定所有的数据包长度为100byte,如果不够则补充至100长度。优点就是实现很简单,缺点就是空间有极大的浪费,如果传递的消息中大部分都比较短,这样就会有很多空间是浪费的,同样浪费的还有流量。

分隔符:用分隔符来确定数据的边界,这样做比较简单也不浪费空间,但数据包内就不能包含相应的分隔符,如果有会造成错误的解析。

数据头:通过数据头部来解析数据包长度,比如用4个字节来当数据头,保存每个实数据包的长度。

个人更推荐数据头方式来确定数据边界,在发送和接收数据时做好规定,每个数据包是不定长的,比如4字节的包头+真实的数据可以根据自己的业务进行扩展,比如上更多的包头或者包尾,加上数据校验等。

我修改一下上面的代码:

客户端

data := []byte("~测试数据:一二三四五~")

conn, err := net.Dial("tcp", ":8899")

if err != nil {

panic(err)

}

for i := 0; i < 2000; i++ {

var buf [4]byte

bufs := buf[:]

binary.BigEndian.PutUint32(bufs, uint32(len(data)))

if _, err := conn.Write(bufs); err != nil {

fmt.Printf("write failed , err : %v\n", err)

break

}

if _, err = conn.Write(data); err != nil {

fmt.Printf("write failed , err : %v\n", err)

break

}

}

服务端

func main() {

l, err := net.Listen("tcp", ":8899")

if err != nil {

panic(err)

}

fmt.Println("listen to 8899")

for {

conn, err := l.Accept()

if err != nil {

panic(err)

} else {

go handleConn(conn)

}

}

}

func handleConn(conn net.Conn) {

defer conn.Close()

for {

var msgSize int32

err := binary.Read(conn, binary.BigEndian, &msgSize)

if err != nil {

break

}

buf := make([]byte, msgSize)

_, err = io.ReadFull(conn, buf)

if err != nil {

break

}

fmt.Printf("recv: %s \n", string(buf))

}

}

执行再看一下输出,没有粘包或者半包的情况

recv: ~测试数据:一二三四五~

recv: ~测试数据:一二三四五~

recv: ~测试数据:一二三四五~

recv: ~测试数据:一二三四五~

recv: ~测试数据:一二三四五~

recv: ~测试数据:一二三四五~

也可以像第一个例子一样用一个指定大小的buf var buf [1024]byte,每次从conn里取出指定大小的数据,然后进行数据解析,如果发现有半包的情况,就再读取一次,加上上次未解析的数据,再次重新解析。


http://chatgpt.dhexx.cn/article/L70w90PB.shtml

相关文章

php处理粘包,Swoole怎么处理粘包

什么是 TCP 粘包&#xff1f; TCP 粘包是指发送方发送的若干包数据 到 接收方接收时粘成一包&#xff0c;从接收缓冲区看&#xff0c;后一包数据的头紧接着前一包数据的尾。 TCP 出现粘包的原因&#xff1f; 发送方&#xff1a;发送方需要等缓冲区满才发送出去&#xff0c;造成…

什么是粘包和拆包,Netty如何解决粘包拆包?

Netty粘包拆包 TCP 粘包拆包是指发送方发送的若干包数据到接收方接收时粘成一包或某个数据包被拆开接收。 如下图所示&#xff0c;client 发送了两个数据包 D1 和 D2&#xff0c;但是 server 端可能会收到如下几种情况的数据。 上图中演示了粘包和拆包的三种情况&#xff1a;…

tcp的拆包和粘包

tcp的拆包和粘包 简介 拆包和粘包是在socket编程中经常出现的情况&#xff0c;在socket通讯过程中&#xff0c;如果通讯的一端一次性连续发送多条数据包&#xff0c;tcp协议会将多个数据包打包成一个tcp报文发送出去&#xff0c;这就是所谓的粘包。而如果通讯的一端发送的数据…

TCP粘包现象

TCP粘包现象 在socket网络编程中&#xff0c;都是端到端通信&#xff0c;由客户端端口服务端端口客户端IP服务端IP传输协议组成的五元组可以明确的标识一条连接。在TCP的socket编程中&#xff0c;发送端和接收端都有成对的socket。发送端为了将多个发往接收端的包&#xff0c;更…

粘包问题及解决方法

如何解决粘包问题 粘包就是连续向对端发送两个或者两个以上的数据包&#xff0c;对端在一次收取中受到的数据包数量可能大于1个&#xff0c;当大于1个时&#xff0c;可能时几个包加上某个包的部分&#xff0c;这这干脆几个完整的包在一起。当然&#xff0c;也可能收到的数据只…

粘包问题

TCP是一个面向连接的&#xff0c;可靠的&#xff0c;安全的流式协议 什么是粘包 粘包是指的是数据和数据之间没有没有明确的分界线&#xff0c;导致不能够正确的传输数据&#xff08;只有TCP会粘包 UDP 永远不会粘包&#xff09;&#xff0c;粘包问题只针对于一切字节流的协议…

粘包现象与解决粘包问题

粘包现象与解决粘包问题 一、引入 粘包问题主要出现在用TCP协议传输中才会出现的问题,UDP不会出现,因为TCP传输中他会服务端会一次性把所有东西一并丢入缓存区,而读取的内容大小有时候没法准确的做到一一读取,所有会存在粘包。 而UDP他传输的时候是吧一个个内容丢过去,不管客…

粘包

粘包 一、什么是粘包二、为什么会粘包三、粘包解决思路 一、什么是粘包 粘包是指发送方发送的若干数据到接收方&#xff0c;而接收方在接收数据时这些数据粘在一起&#xff0c;后一包数据头紧接着前一包数据尾部。 二、为什么会粘包 首先了解一下socket收发消息原理&#xff1…

网络通讯中粘包的处理

参考&#xff1a;网络通讯中粘包的处理 - 走看看 在网络通讯中&#xff0c;不仅仅是TCP通讯&#xff0c;也包括串口通讯中&#xff0c;我们经常会遇到数据包粘连的问题&#xff0c;本文详细介绍粘包问题产生的原因和解决办法。 一、粘包定义 TCP 传输中&#xff0c;客户端发送…

什么是粘包?

TCP/IP 协议簇建立了互联网中通信协议的概念模型&#xff0c;该协议簇中的两个主要协议就是 TCP 和 IP 协议。TCP/ IP 协议簇中的 TCP 协议能够保证数据段&#xff08;Segment&#xff09;的可靠性和顺序&#xff0c;有了可靠的传输层协议之后&#xff0c;应用层协议就可以直接…

【HUST】信息系统安全:Ret2libc多函数调用,ASLR两种情况(2)

注&#xff1a;感谢这位大佬的帮忙&#xff0c;没有他我估计还在github里面或者其他博客里面瞎找小雨aaa Ret2libc:Return to libc,顾名思义&#xff0c;就是通过劫持控制流使控制流指向libc中的系统函数&#xff0c;从而实现打开shell等其他工作。 在本次作业中&#xff0c;…

Linux ALSA音频工具

参考&#xff1a; ALSA 音频工具 amixer、aplay、arecord Linux Alsa ALSA的配置文件 音频录制——arecord 音频播放——aplay 音频配置——amixer alsamixer与amixer的区别 alsamixer是Linux音频框架ALSA工具之一&#xff0c;用于配置音频各个参数; alsamixer是基于文本图形…

[pwn]ROP:绕过ASLRNX

[详细] ROP&#xff1a;绕过ASLR&NX 这次使用的程序是Defcon - 2015初赛题目&#xff0c;r0pbaby&#xff0c;也是一道经典的pwn题目了。 程序链接&#xff1a;https://pan.baidu.com/s/1kr6z_crZfW7qNjtASmRMGw 提取码&#xff1a;eajs NX策略是指在栈中的代码不会被执行…

ORA-445报错与ASLR

数据库多次出现ORA-00445: background process "J002" did not start after 30 seconds报错及ORA-3136错误 查看相关文档(文档 ID 1600807.1)&#xff0c;两个报错都可能与内存压力过大有关 另外关于ORA-00445还有另一篇文档提到&#xff0c;在Oracle启用ASLR会无法…

[二进制学习笔记]Ubuntu20.04关闭开启ASLR

文章目录 Ubuntu20.04关闭开启ASLR Ubuntu20.04关闭开启ASLR ​ ASLR(Address space layout randomization)是一种针对缓冲区溢出的安全保护技术&#xff0c;通过对堆、栈、共享库映射等线性区布局的随机化&#xff0c;通过增加攻击者预测目的地址的难度&#xff0c;防止攻击者…

ASLR和PIE的区别

总结&#xff1a;ASLR 不负责代码段以及数据段的随机化工作&#xff0c;这项工作由 PIE 负责。但是只有在开启 ASLR 之后&#xff0c;PIE 才会生效。

【HUST】信息系统安全:Ret2libc多函数调用,ASLR两种情况(1)

Ret2libc:Return to libc,顾名思义&#xff0c;就是通过劫持控制流使控制流指向libc中的系统函数&#xff0c;从而实现打开shell等其他工作。 在本次作业中&#xff0c;我们的目标是通过运行stack.c程序来访问系统上的/tmp/flag程序的内容&#xff0c;其中&#xff0c;可以看到…

Linux ALSA声卡驱动之五:移动设备中的ALSA(ASoC)

1. ASoC的由来 ASoC--ALSA System on Chip &#xff0c;是建立在标准ALSA驱动层上&#xff0c;为了更好地支持嵌入式处理器和移动设备中的音频Codec的一套软件体系。在ASoc出现之前&#xff0c;内核对于SoC中的音频已经有部分的支持&#xff0c;不过会有一些局限性&#xff1a…

astrill android,Astrill

你想知道你所用的网络速度是多少吗&#xff1f;你想在全球任何地方都可以使用到手机网络吗&#xff1f;你想在需要下载文件时定位到信号最强的地方进行传输吗&#xff1f;小编今天为企业家和用户安利一款手机测速游戏——Astrill APP&#xff01;用户可以随时随地的查询到自己的…

Linux下 ASLR功能与 -no-pie 选项说明

一. Linux下ASLR功能 1. ASLR 技术介绍 ASLR 技术是一种针对缓冲区溢出的安全保护技术。 ASLR&#xff0c;全称为 Address Space Layout Randomzation&#xff0c;地址空间布局随机化。ASLR 技术在 2005 年的 kernel 2.6.12 中被引入到 Linux 系统&#xff0c;它将进程…