打了删除线的,都是有问题的错误的描述。html
对于这类问题,发现仍是最终要回归到经典书籍,即牛逼的unix网络编程 这样的书,否则看再看的文章和网络资料,都不必定能看得懂,由于网络资料和网友的理解不必定很全面,他们最原始的最源头的参考资料,也就是这么几本书。无非是,他们肯比较吃苦,把书多看了几遍,能用本身的语言表达出来,固然,能够确定的是,只要是复述别人的话,确定是有很多的漏洞的。后面的人,须要理解清楚,就惨了。最终,仍是得,把经典书籍给捡起来,和他们同样,得多看几遍。java
最关键的地方就是这里了。要深刻的真正的理解为何会发生拆包和粘包的状况。直接看unix网络编程这一本书就够了。程序员
协议分层 编程
握手:须要三个分节 数组
握到一半的时候,叫半链接。这个时候,还不能进行数据通讯。只有等彻底创建链接,即状态变为established的时候,才能够读写数据。服务器
关闭:须要四个分节,由于确认分节和响应分节是分开的。具体缘由是,由于响应分节超过1s,就先发确认分节。 网络
关到一半的时候,叫半关闭。这个时候,仍然能够进行通讯。由于有可能,路由在路上的数据尚未到达目的地。数据结构
tcp socket 11种状态-状态转换图 架构
握手链接、读写数据、关闭的完整流程 app
tcp socket在内核里的缓冲区内存
操做分节和确认分节
无论是什么操做,好比握手操做或者关闭操做,都有一个专门的分节来表示它们。而每一个操做分节都须要确认,因此也就有了确认分节,确认分节的内容是ACK操做分节的序号+1。例如,ACK M+1。操做分节的序号,指的是,当前数据的分节序号,就是一个编号而已。
数据按是否完整,分为两块(或者说,有两种叫法)
1.数据报文
要发送的完整数据
2.数据包
数据子包 分节 数据报,反正,无论什么叫法,就是只是完整数据的一部分。
并且,分节,在每一层都有可能往下拆分为多个子分节。也就是说,只有应用层的数据才是完整的数据报文,其余的层,包括传输层tcp 网络层ip 数据链路层,都是子分节。
另外,不一样层,对分节的叫法,也不同,但其实,本质上都是分节,即表明的是不完整的子数据:
1.tcp
分节
2.ip
数据报datagram
3.数据链路层
帧frame
1.拆分
是由于数据太大
2.合并
是由于数据过小
具体细节
tcp socket 内核缓冲区:包含发送缓冲区和接受缓冲区,客户端和服务器都有两个缓冲区
1.何时发生拆包?
数据比缓冲区大。就会被拆成多个独立的分节。
2.何时发生粘包?
数据比缓冲区小,就有可能把多个数据拼接为一个分节。
可是,网络协议的目的,整体上来讲,是要避免减小拆包和粘包的状况,由于拆包和粘包以后,在路由到目的地的时候顺序不一致,接受度要从新还原顺序。这是浪费。
并且,在网络协议的每一层,都有可能发生拆包和粘包。
中间经历不少路由器
TCP协议层已经解决粘包 拆包问题,为何还要应用层去解决呢 TCP协议层标记了数据包的顺序,可是接受方收到后如何排序?数据不是以流的形式存在吗?总数据长度固定,这个能够区别不一样的请求数据。可是接收方怎么解决同一次请求的不一样数据包排序的问题?
数据包的顺序不须要应用层解决,由于tcp协议层和操做系统内核已解决。
本质是要识别某一次数据的总长度和前后顺序
1.总长度肯定
2.前后顺序编号 //这个是TCP网络协议层已经解决的,不须要应用层解决
全部的解决方法都是围绕以上两个问题,而后解决以上两个问题。
总结
上面的理解都是有问题的,错误的。
首先,关于顺序编号,有两种1.每一个数据包(即分节)都有编号 2.分节里的每一个字节,都有编号。不过,无论是哪种编号,目的都是为了在接收端从新排序还原数据原始顺序。
其次,没有什么总长度,只有每一个数据包的长度。固然,每一层的数据包都有可能被拆分红多个分节(即子包),因此,每一个数据包的长度只是知道它本身(即当前数据包)的长度,而不知道要发送的整个数据的总长度。因此,这个时候,才须要咱们应用层去解决拆包和粘包的问题,说白了,就是要找到两次数据的边界在哪里,好比,我聊天的时候发送了两次数据(两条消息),所谓的拆包和粘包,就是要解决如何区别这两个数据的问题。固然,短数据,通常就一个数据包。
应用层才须要解决拆包 粘包的问题,不过,咱们具体开发程序的时候,通常使用netty这样的通讯框架,也就是说,netty这样的通讯框架,已经帮助咱们处理了拆包 粘包的问题。netty这样的通讯框架,处理的就是传输层tcp socket的拆包 粘包问题。
具体如何处理?
netty有不一样的解决方案类,这些解决方案类,每一个都是对应一个解决方案。具体的解决方案,就是:
1.分隔符标志
使用分隔符,区分数据
2.总长度
使用总长度,区分数据。注意,这里的总长度,是应用层协议的数据的总长度,而不是传输层的总长度,服务器端和客户端两边就经过应用层协议的报文的数据结构的总长度字段,来区分数据。
这他妈都是问题啊,一堆问题,说明你根本没有理解清楚。只是知道一点理论。这不是学习的好方法啊。
无论是拆包,仍是粘包,本质上要解决的问题是,区分两次发送的数据。具体的办法是,
1.要么使用分隔符区分
2.要么使用总长度
使用分隔符,好比,http,使用换行符。
总长度,好比,netty。
通常的应用层协议都是使用总长度。
请求行
头部字段
内容
以上三项是经过换行符分离。若是包含了换行符,那么转义字符。
以前有总结过。解决方案是不一样的解决方案有不一样的类。
细节。参考那篇笔记。
原理确定是和前面提到的原理同样。
客户端主动关闭时的最后一个状态
客户端和服务器,都有11种状态。
状态转换图
总共好几张图,很重要,很经典
接受端-内核缓冲区,包含了已使用和未使用这些数据,而且会把这些数据发送给发送端。而这就是所谓的窗口大小,知道了接受端的剩余大小,发送端就能够控制发送速度和发送数据的流量大小。
网络和协议这一块,全部的官方标准和规范,就是RFC文档。
User datagram protocol用户数据报文协议。
和TCP最大的区别就是,不可靠。
为什么要分层?分层的本质?每一层的本质?
每一层解决一个问题,不分层也能够,可是,这样的话,就是一个层解决全部问题。
这就MVC框架同样,每一层解决不一样的问题。
好比,IP网络层,包含了源IP和目的IP,主要做用是找到对方机器,把数据路由过去。
而,TCP传输层,是确保数据传输过程中的可靠性。具体来讲就是1.接受者必须收到数据2.数据不能丢失,不然服务器重发3.数据不能重复,不然客户端去重。
由于链接的时候,服务器的确认和同步一块儿发送。
而,关闭,服务器是分开发送。即先发送确认,再发送关闭。
为何链接和关闭,服务器端,一个能够一块儿发送,一个只能分开?这个是根据响应时间来肯定的。即,若是响应(无论是链接-同步Syn,仍是关闭-FIN,仍是读写数据-响应,这三种状况其实本质上都是响应)的时间是毫秒级别200ms,那么一块儿发送,若是是秒级别1s,那么分两次发送,先发送确认,后发送响应。
链接的syn分节,是不带数据的,只包含头部字段。
通常都是客户端主动关闭。早期http1.0是短链接,因此是服务器主动关闭,后期1.1是长链接,客户端先关闭。
TCP协议是可靠的协议,主要确保几点:
1.数据有序
编号。
每一个分节编号(好比,12345)。
每一个字节编号(好比,第一个分节1~1000,第二个分节1000~2000)。
编号的目的是,由发送端编号,接受端收到数据以后,若是乱序,那么从新还原顺序。
2.数据不能丢失
丢失是指接受端没有收到,发送端要重发。具体实现原理是?接受端是否接受到数据,须要发送确认给发送端。
3.数据不能重复
接受端,若是收到重复分节数据,那么抛弃重复数据,由于数据分节有编号。
正由于非应用层的协议,确保了数据有序,如今剩下来的惟一要解决的问题,就是怎么区分不一样的数据。
由于数据是流,TCP协议的socket是基于字节流来通讯的。
怎么区分?
首先要确认一点的是,必须由应用层协议来解决。
其次,就是具体的解决方法的问题,通常有两种方法:
1.分隔符
2.应用层协议的数据报文的数据结构,有一个数据报文的总长度字段
2个数据包变成一个包 是粘包
2个包变成了3个包 是拆包
解释
首先,要明白两个概念
1.报文/消息/文件
当前这一次发送的完整内容
2.数据包
一个大的报文1若是一次发送不完 会被拆分为多个小的数据包1数据包2
其次,还要知道tcp协议里包含了缓冲区这个东西 发送数据的流程是:
用户进程——操做系统内核的缓冲区——网络——目标机器
在用户进程——内核的缓冲区
这一步(这一步是完整报文),数据的流程是这样的,
1.先把数据复制到缓冲区
2.缓冲区的数据何时到网络 看状况。因此在缓冲区——网络这一步(这一步是数据包-完整报文的一部分),每一个数据包的内容会出现如下几种状况:
1.报文1
2.报文2
3.报文1的部分数据 + 报文2 //3 4是拆包,就是有一个报文的数据被拆分红了两部分
4.报文2的部分数据 + 报文1
5.报文1 + 报文2 //5是粘包 就是两个报文在一个数据包里
为何会出现粘包和拆包的状况?
发生TCP粘包、拆包主要是因为下面一些缘由:
应用程序写入的数据大于套接字缓冲区大小,这将会发生拆包。
应用程序写入数据小于套接字缓冲区大小,网卡将应用屡次写入的数据发送到网络上,这将会发生粘包。
进行MSS(最大报文长度)大小的TCP分段,当TCP报文长度-TCP头部长度>MSS的时候将发生拆包。
接收方法不及时读取套接字缓冲区数据,这将发生粘包。
……
总结
关键在一点
1.缓冲区的数据何时到网络 不肯定 要看状况
另外
2.缓冲区的大小很大程度上决定了何时缓冲区数据到网络
之因此会发生所谓粘包 拆包的缘由是由于tcp协议这一层的数据是字节流,接受数据方不知道数据何时该结束。
粘包与拆包是因为TCP协议是字节流协议,没有记录边界所致使的。 因此如何肯定一个完整的业务包就由应用层来处理了。 (这就是分包机制,本质上就是要在应用层维护消息与消息的边界。) 分包机制通常有两个通用的解决方法:
1,特殊字符控制,例如FTP协议。
2,在包头首都添加数据包的长度,例如HTTP协议。
做者:祖春雷 连接:www.zhihu.com/question/37… 来源:知乎 著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。
为何是应用层解决拆包 粘包?tcp层协议不是有报文长度字段吗?
只能在上层/应用层协议(即应用层)解决这个问题。几种方法
1.换行符
2.头部和数据部分
头部的长度字段规定报文长度
3.固定长度
netty怎么解决?
以上三种方法 netty都有对应的类。
转义字符? 转义为何能解决问题? java转义字符?
要发送的完整内容
报文和数据包的区别
1.报文是完整的信息 即你要发送的内容 好比 聊天文字 文件 http请求消息/响应消息
2.若是是短消息 好比聊天文字 一个数据包就够了 这个时候数据包就是报文 基于udp报文协议
若是是大数据 好比文件 一个数据包不够 就多个数据包 这个时候一个完整报文分为多个数据包 基于tcp数据包协议
blog.51cto.com/91xueit/135…
不一样协议层的叫法可能不同
总结一下。frame对应mac,packet对应ip,datagram对应udp,segment对应tcp,message对应app。但愿对你们有用。
blog.csdn.net/wang7dao/ar…
http协议的报文
1.请求
请求行
请求头部字段 //包含请求体的长度字段
内容
2.响应
同上
字节流的字节可能乱序 接受方经过字节序号还原发送顺序。
为何会乱序
由于两个电脑之间传输数据 中间通过不少的路由器路由转发 不一样的报文走的多是不一样的路径 到达目标ip的时间前后顺序可能不同
是字节序号仍是数据包序号
都有编号。
无论是哪种序号 编号的目的都是为了解决接收方还原数据顺序的目的。
接收方具体是如何实现还原的?
就是tcp缓冲区剩余内存大小
分类
有发送缓冲区和接收方缓冲区
是什么
两个套接字 各自都有写和读缓冲区。
套接字的缓冲区是基于tcp协议的缓冲区,两者一一对应
套接字编程时 有发送缓冲区和接受缓冲区字段能够设置值的大小
咱们平时用到的套接字其实只是一个引用(一个对象ID),这个套接字对象其实是放在操做系统内核中。这个套接字对象内部有两个重要的缓冲结构,一个是读缓冲(read buffer),一个是写缓冲(write buffer),它们都是有限大小的数组结构。
当咱们对客户端的socket写入字节数组时(序列化后的请求消息对象req),是将字节数组拷贝到内核区套接字对象的write buffer中,内核网络模块会有单独的线程负责不停地将write buffer的数据拷贝到网卡硬件,网卡硬件再将数据送到网线,通过一些列路由器交换机,最终送达服务器的网卡硬件中。
一样,服务器内核的网络模块也会有单独的线程不停地将收到的数据拷贝到套接字的read buffer中等待用户层来读取。最终服务器的用户进程经过socket引用的read方法将read buffer中的数据拷贝到用户程序内存中进行反序列化成请求对象进行处理。而后服务器将处理后的响应对象走一个相反的流程发送给客户端,这里就再也不具体描述。
做者:老錢 连接:juejin.im/post/5b344a… 来源:掘金 著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。
注:核心流程:用户态——内核态:缓冲区。 所谓的套接字/tcp 缓冲区就是内核态的缓冲区,这个缓冲区在内存,全部缓冲区都是在内存。
用户进程的缓冲区和操做系统内核tcp/套接字的缓冲区?
udp有没有缓冲区?
没有
做用
1.工做流程
数据先到操做系统内核缓冲区,内核有专门线程处理缓冲区的数据用于读写。
2.具体细节
缓冲区满了 一次性读写?不是。看状况。具体见下文。
3.缓冲区本质的做用 或者说好处
缓冲区与窗口大小
两者同样
缓冲区的数据什么时候被处理 即被发送到网络?
TCP协议独立于 write()/send() 函数,数据有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断积压,屡次写入的数据被一次性发送到网络,这取决于当时的网络状况、当前线程是否空闲等诸多因素,不禁程序员控制。
缓冲区的特性
这些I/O缓冲区特性可整理以下:
I/O缓冲区在每一个TCP套接字中单独存在;
I/O缓冲区在建立套接字时自动生成;
即便关闭套接字也会继续传送输出缓冲区中遗留的数据;
关闭套接字将丢失输入缓冲区中的数据。
好比
1.服务器
阻塞接受客户端链接
2.客户端
同上
unix网络编程