tcp-报文
深入理解tcp报文
包含
1.头部
2.数据
主要是头部的字段
画一下tcp报文
1.有哪些字段
2.每个字段的大小
第一行,4个字节,port //用于绑定到哪个程序
第二行,4个字节,当前分节的编号 //用于接收端还原分节的发送顺序
第三行,4个字节,接收端想要接受的下一个报文编号——这个字段,只有在接受端的确认报文里才有值!
首部长度字段 //报文/首部起始位置和数据起始位置
标志字段,共6位
1.紧急报文位
报文排队队列本来是按顺序发送报文,现在是紧急报文,优先发送,不需要排队。
2.确认位
确认 ACK (Acknowlegemt)
当 ACK = 1 的时候,确认号(Acknowledgemt Number)有效。
一般称携带 ACK 标志的 TCP 报文段为「确认报文段」。
TCP 规定,在连接建立后所有传送的报文段都必须把 ACK 设置为 1。
3.优先级高位
推送 PSH (Push)
当 PSH = 1 的时候,表示该报文段高优先级,接收方 TCP 应该尽快推送给接收应用程序,而不用等到整个 TCP 缓存都填满了后再交付。
注:注意和紧急报文位的区别,一个是不用排队,一个是不用等到TCP socket缓冲区满了才发送数据,虽然关注的切入点有点不一样,但是二者的目的是一样的,都是为了尽快优先发送该报文数据。
4.请求连接报文位
同步 SYN (SYNchronization)
当 SYN = 1 的时候,表明这是一个请求连接报文段。
一般称携带 SYN 标志的 TCP 报文段为「同步报文段」。
在 TCP 三次握手中的第一个报文就是同步报文段,在连接建立时用来同步序号。
对方若同意建立连接,则应在响应的报文段中使 SYN = 1 和 ACK = 1。
5.关闭连接报文位
终止 FIN (Finis)
当 FIN = 1 时,表示此报文段的发送方的数据已经发送完毕,并要求释放 TCP 连接。
一般称携带 FIN 的报文段为「结束报文段」。
在 TCP 四次挥手释放连接的时候,就会用到该标志。
窗口大小 //其实就是,接收端的tcp
socket缓冲区还有多少空间,通知给发送端,发送端就知道了要发送多少数据,控制一下发送流量,不然发送了过多的数据,接收端也无法接受,就直接丢弃了。
窗口大小 Window Size
占 2 字节。
该字段明确指出了现在允许对方发送的数据量,它告诉对方本端的 TCP 接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。
窗口大小的值是指,从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量。
例如,假如确认号是 701 ,窗口字段是 1000。这就表明,从 701 号算起,发送此报文段的一方还有接收 1000 (字节序号是 701 ~ 1700) 个字节的数据的接收缓存空间。
校验和 //其实就是摘要算法,目的是发送端和接收端的数据一致,没有被中介篡改
校验和 TCP Checksum
占 2 个字节。
由发送端填充,接收端对 TCP 报文段执行 CRC 算法,以检验 TCP 报文段在传输过程中是否损坏,如果损坏这丢弃。
检验范围包括首部和数据两部分,这也是 TCP 可靠传输的一个重要保障。
头部
1.前面20个字节固定大小不变
2.后面是4个字节的N倍,也就是说,可以有N个4个字节,不够的填充空白即可
选项字段
是什么
就是附加字段
有哪些附加选项字段
MSS
参考
jerryc8080.gitbooks.io/understand-…
官方
RFC文档
Unix网络编程
tcp-分节MSS:本质是什么
从应用层——Tcp socket,不是已经有了tcp socket缓冲区吗?
这个缓冲区不就是用来给数据分节的吗!
既然在tcp这一层已经分节了,还要tcp-MSS分节干嘛?tcp-MSS是为了给下一层ip进行分节!
Tcp socket缓冲区多大?
MSS的本质到底是什么?
1.
2.
ip-分节MTU:本质是什么
拆包 粘包的三个原因/三个场景
分层
应用层
TCP //一个数据分为多个TCP分节
IP //一个TCP分节分为多个IP分节
链路层 //一个IP分节分为多个链路分片
物理层
原因
拆包 粘包的五种可能?
MSS
是什么?
tcp分节的最大字节数量(不包括tcp首部的20个字节)。
ic分节(还要再减去ip首部的20个字节)
所以,MSS1460=MTU1500-40
作用
避免数据过大,导致ip分成多个分节,因为分节之后还需要重组,即接收端还原发送顺序,这个需要耗费资源。
www.zhihu.com/question/19…
简单来说是这样的,协议设计之初网络设备的性能都不好,如果一个TCP报文被分片,变成一个TCP+IP报文,对端需要先进行IP报文重组,再对TCP传输的数据重组,很耗性能。所以如你所说,就是为了避免IP分片
最佳实践
这个值,越大越好,因为每个分节的tcp首部20个字节是固定的,如果每次数据太少,这就是浪费资源。
两个大小,分别存储在哪里?
1.一个是分节的大小(最大值)
具体的值,存储在在选项字段里
2.一个是接受缓冲区的剩余值
首部有专门的字段(即所谓的窗口大小)
两个方向的MSS值允许不一样
官方文档 作者:邓沐阳 链接:www.zhihu.com/question/19… 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
挖坟~ MSS选项最先出现在RFC 879上面,RFC 879由RFC 6691更新,RFC 6691好像暂时还没吸纳为标准,如果空谈误国的话,看一下这两个文档就可以了,很短,不过好像需要翻墙。 断章取义截取几行文档内容: 879: 3. The TCP Maximum Segment Size Option TCP provides an option that may be used at the time a connection is established (only) to indicate the maximum size TCP segment that can be accepted on that connection. This Maximum Segment Size (MSS) announcement (often mistakenly called a negotiation) is sent from the data receiver to the data sender and says "I can accept TCP segments up to size X".
- The Relationship between IP Datagram and TCP Segment Sizes The relationship between the value of the maximum IP datagram size and the maximum TCP segment size is obscure. The problem is that both the IP header and the TCP header may vary in length. The TCP Maximum Segment Size option (MSS) is defined to specify the maximum number of data octets in a TCP segment exclusive of TCP (or IP) header. To notify the data sender of the largest TCP segment it is possible to receive the calculation of the MSS value to send is: MSS = MTU - sizeof(TCPHDR) - sizeof(IPHDR) On receipt of the MSS option the calculation of the size of segment that can be sent is: SndMaxSegSiz = MIN((MTU - sizeof(TCPHDR) - sizeof(IPHDR)), MSS) 可以看出是通过MTU和ip首部,tcp首部大小来计算的。
而6691: 2. The Short Statement When calculating the value to put in the TCP MSS option, the MTU value SHOULD be decreased by only the size of the fixed IP and TCP headers and SHOULD NOT be decreased to account for any possible IP or TCP options; conversely, the sender MUST reduce the TCP data length to account for any IP or TCP options that it is including in the packets that it sends. The rest of this document just expounds on that statement, and the goal is to avoid IP-level fragmentation of TCP packets. The size of the fixed TCP header is 20 bytes [RFC793], the size of the fixed IPv4 header is 20 bytes [RFC791], and the size of the fixed IPv6 header is 40 bytes [RFC2460]. The determination of what MTU value should be used, especially in the case of multi-homed hosts, is beyond the scope of this document.
所以,MSS的目的是知会对方己方的MTU值,因此可以说是为了减少对方发包过大导致的分片。
参考
medium.com/fcamels-not… //这篇文章太牛了,写的很好!
可以看看TCP/IP详解:第一卷协议 P179页 18.4最大报文段长度和P254 24.2路径MTU发现。
baike.baidu.com/item/MSS/35… //百度百科 zh.wikipedia.org/wiki/最大分段大小 //维基百科
MTU
是什么?
最大传输单元。
MTU更底层,就是数据链路层和物理层,能够传输的数据大小
以下是个人的一点理解:
MSS是TCP一次能够传输的数据(不包括协议头的开销)的最大值,在传输过程中是会变化的,客观地反映了信道和两个客户端的处理能力的变化情况。
假设客户端出能力能很强,一般情况下,当通信双方约定好MSS后,会尽量按照MSS传输数据,以期达到信道利用率的最大化,然而当信道条件改变后,即变好了或者变坏了,如果此时仍不改变每次发送的数据的数量,就会出现信道利用不充分或者信道过利用(导致拥塞、最终你发送的数据会被丢弃)的情况,因此,MSS可以说架起了信道与应用程序之间的桥梁,信道好,MSS大,信道坏,MSS小,他们之间的联系可以通过TCP的反馈协议(ack)实现,这也是TCP与UDP的区别。
当然还有一个概念是MTU,这个在更底层了,说明了在物理上信道支持的最大数据量,因此,MSS应该比MTU小,正常情况下,MSS=MTU-IP包头长-TCP包头长~~~~
作者:汪建 链接:www.zhihu.com/question/19… 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
参考 blog.crhan.com/2014/05/mtu…
MTU和MSS的区别?
区别?
值的大小差不多。可以看做等值!而且实际的值,MSS分节就是使用的MTS的值。
MSS(1000个字节) = MTU(1000个字节) - tcp头部大小(20个字节)
ip分节和tcp分节的区别?
ip分节是什么?怎么传输?
进行MSS协商的另一个好处是能够提高网络带宽的利用率。在一个局域网中进行通信的两个节点可以选择一个比较大的MSS,使得报文段封装成IP分组时能够充分利用网络的带宽。但是实际上在一般的Intenet 环境中,为连接选择一个合适的MSS是相当困难的。这是因为MSS的取值过大或过小都会影响网络和TCP的性能。如果报文段太小,将会大大降低网络的利用率。但如果报文段太大也可能影响网性能。
这是由于长IP分组在网络中传输时往往需要被分片传输。分片和重组的过程自然将带来一定的网络处理开销。而且IP分组被分片后独立传输,任何一个分片出现错误或丢失都将导致整个分组被丢弃,这也意味着整个报文段丢失,TCP只能对整个IP分组进行确认和重传。由于在IP通信子网中分组丢失的概率总是存在的,因此MSS的增加所导致的分片将会使报文段成功达到目的端的概率下降,从而影响TCP的性能和和降低网络的吞吐率。
参考
baike.baidu.com/item/MSS/35…
tcp报文-选项字段
是什么?
可选字段
有哪些选项?
1.最大分节大小MSS
1000个字节(千位数级别)
3.发送缓冲区和接受缓冲区的大小
10000个字节(万级别)
缓冲区必须是MSS分节的倍数,而且是分节的好几倍,因为要存放多个分节,数据分节 + 确认分节,还有数据分节副本。
最大分节大小
分节是如何在路上传播的?
写数据和读数据,走的是不同的线路。网线有7根线,不同的线专门读或写。
参考 unix网络编程
不同层对分节的叫法
1.tcp segment段/分节
2.ip package包/数据包
3.链路层 frame帧
tcp-ip分节
是什么?
就是tcp——ip,分成多个ip分节。
就是一个tcp报文/分节,被拆包为多个ip分节。
应用层-tcp分节
应用层数据比内核tcp socket发送缓冲区要大或小。
1.大
拆包
2.小
粘包
接收端-内核tcp socket剩余缓冲区大小
是什么?
全双工
不管是建立连接,还是关闭连接,都需要双方共同确认这件事情完成了,才是完成了。
比如,关闭,双方都要关闭socket连接,释放资源。
netty通信协议
支持以下协议
1.公开协议
Http
Websocket
2.私有协议
netty自己定义的内部协议
基本上每个软件,都会根据自己的业务特征,去定义自己的数据的通信协议。一切的目的,就是为了快!
心跳机制的实现
Ping-pong。其实就是一般的普通的请求数据和响应数据,只不过ping-pong机制的数据量更少。因为它只需要判断网络是否连接通畅。
IO是单向流,NIO是基于通道的双向流
1.IO是单向流。就是读和写流类是分开的独立的类。
2.而,NIO,是双向流,基于channel通道。
且,基于注册事件机制,即多路复用。本质就是,一个连接处理多个任务,复用socket连接。
还有缓冲区。
http为什么不支持全双工?
设计规范的时候,它的目的就是为了避免全双工。因为只要全双工,也就是服务器可以主动向客户端写数据,那么必然保持长连接,而长连接非常耗费资源,所以http最初设计的时候就放弃了全双工,因为TCP本来就支持全双工,http是基于TCP,所以http只要想用TCP的全双工特性是完全没有问题的。
只不过,它最初的设计规范和目的,就是不需要全双工。避免过多长连接把服务器瞬间拖垮。
1.http1.0
完全不支持长连接。
服务器发送响应之后,就主动关闭连接。//只有http协议,是服务器主动关闭,一般协议都是客户端关闭!
2.http1.1
通过keep-alive支持长连接。
不过,这个长连接不彻底,具体来说,就是只保持一段时间,这个时间很短,只有20S。然后,超过这段时间,服务器还是要主动关闭。
3.H5的websocket
4.Http2全双工
所有的应用层协议支持全双工,都是因为TCP支持全双工,也都是基于TCP socket的全双工来开发应用层协议。
所以,传输层除了TCP/UDP,其他协议都是应用层协议,而且都是基于TCP socket。
为什么TCP是可以保持长连接的,而基于TCP的HTTP却不能?
可能这个问题本身表述就不是很清楚,但我也想不出其他合适的词汇了。直接上例子吧:我们在做web应用的时候有时会碰到需要实时推送的情况,但是HTTP协议本身是不支持长时间的连接的,因为HTTP本身是request/response型的协议,可以理解为半双工通讯。
而TCP 是支持长连接的,是通过heartbeat来进行连接的保持。这样,就引出我上面提到的问题了。
在解答这个问题之前,还有几点是要说明的:http1.1中其实也有长连接的概念,具体到header参数就是keep-alive,但是这个keep-alive是一个数值,比如20s,就是这个http连接对应的tcp连接会保持20S,这个时间段过来的http连接会复用上次的tcp连接。如果没有的话,那么会开启一个新的tcp连接。而tcp协议里面的keep-alive就是heartbeat发送的包内容,表示“我还活着”。
接下来回答一下上面那个问题:其实很简单,我们混淆了“基于TCP协议”这个概念,TCP本身是一个传输层的协议,就是用来作数据传输的,也决定了它必然是全双工,可以保持连接的特性。再来看下http协议,一种request/response型的协议,为什么要做成request/response这种类型呢,因为server端要服务的client太多了,如果每一个连接都保持而不断开,那么服务器的IO很快就会被堵死了。所以http基于tcp,并非就是全部利用的tcp的特性,在http连接建立之前,的确是需要tcp三次握手建立tcp连接,然后利用这个tcp连接传输http包数据,服务端收到请求的数据后,发送对应的response,之后便关闭了这个tcp连接(如果没有keep-alive)。
再回到刚才的例子:其实现在解决这种实时推送的方案还是很丰富的,比较主流的应该是利用websocket协议来实现。当然,其他的比如:ajax实现的轮询等。就不细讲了,感兴趣就自行Google吧。
参考
kuaibao.qq.com/s/20180312G…
zhangchenchen.github.io/2017/01/10/…
为什么握手三次,关闭四次?
因为一开始,没有数据分节,在路上传播。即一开始,客户端和服务器还没开始互相读写数据呢。所以,服务器把确认分节和响应分节一起发送。
而,建立连接之后,客户端关闭,服务器的确认和响应要分开两次发送。因为,响应分节要晚一点发送,而如果1秒内没有发送,确认分节和响应分节就要分开两次发送,确认分节先发,响应分节后发。
那为什么响应会这么慢呢?本质原因是因为,建立连接之后,客户端和服务器可能一直在读写数据,所以,关闭的时候,很可能路上的数据还没到达还没处理完,所以先等数据处理完,然后再关闭,即响应。
什么是丢包?
信号在铜线等介质的传输过程中,会衰减。
比如,发送10001111,接受10001110,那么数据校验算法的时候发现数据的校验值不一致,类似hashcode不一样,说明接受到的数据和源数据不一样。这个时候,接受端会丢弃数据,这就是所谓的丢包!
丢包之后,接收端响应到发送端,发送端重发数据。
丢包率,只是表示当前网络是否通畅。不是说数据真的丢了!
网线到底是怎么传输二进制数据的?
一根网线,在同一时刻,肯定只能往一个方向写一个二进制数据。根据震荡频率,一秒就是N多个二进制数据。那么,对方在同一时刻,也肯定只能接受一个二进制数据。
多跟网线,就是同时多位二进制数据。
参考
lvwenhan.com/操作系统/485.ht… //重点看这篇文章,系列文章。最好!
zhidao.baidu.com/question/69… //这个也还可以!
zhidao.baidu.com/question/32… //下面的基本上不用看了!
通信协议的数据格式:文本数据和二进制数据?
1.文本数据
Json
Xml
2.二进制数据
Http协议的多媒体数据类型。
还有,Google probuffer这类二进制数据框架。等等。
半双工和全双工的本质区别?
半双工,这个好理解。就是,同一时刻,只有一方向另一方写数据。
全双工,就是同时双方都可以读写数据。具体的实现原理是?读写的时候,标记是哪一方来的数据分节就可以了,这样就能区分是哪一方发送的数据了。
但是,最为本质的原因,还是因为网线电路的原因。
简单点说,就是网线有8根线,就是8个电路,其中有的线是专门用于写数据,有的线是专门用于读数据。
所谓全双工,就是首先要确保网线必须具备同时读写的功能。而想要具备同时读写的功能,一定是因为,有多跟线,且不同线,有的用于写有的用于读。
那为什么http,就不能全双工呢?
netty处于一个什么位置?基于Java NIO的通信框架。其他,不负责处理。
比如,如果要实现一个Java项目的http服务器,需要自己基于netty实现。
不过,netty,其实是提供了http协议栈的支持的。
所以,基于netty JavaNIO和netty提供的http协议栈支持。比较容易,开发Java项目形式的http服务器。与Tomcat这样的重量级容器稍有区别。
数据格式 1.Xml 2.json
其实,不论是哪一种格式,本质上,包括形式上,就是一个字符串。只不过字符串的格式有点不一样。
但不管是哪种数据格式,都有第三方开源软件来专门做这个事情,这个事情,指的是,数据格式转换。类如,xml/json和对象之间的转换。
由此,我们可以看到,netty的目的主要是解决哪些问题?哪些问题又不应该由通信框架netty处理? 现总结如下 1.netty解决通信框架+通信协议 第一,解决通信的问题。这个是基于Java NIO。 第二,解决通信协议的问题。包括TCP socket(实际上是Java NIO多路复用/注册事件机制),http协议,websocket协议。 2.netty不解决不同格式的数据类型和对象之间的转换 这个转换工作,由第三方开源软件完成。
netty-通信协议
支持 1.TCP 2.http 3.websocket
全都支持!
半双工 http。因为http协议是基于请求和响应。这两步,有先后顺序。这是BS架构。
而CS架构,基于传输层协议TCP socket,可以同时读写。
浏览器客户端和服务器技术的发展史 1.单向-基于http 同时,只能单向写或读数据。 2.双向-基于http的轮询 比如1S一次,即一秒浏览器向服务器请求一次。 而且,因为请求频繁,连接不能关闭,所以必然要使用长连接。 可是,长连接,又非常耗费资源。 3.双向同时读写-H5的websocket 本质上,还是基于TCP socket。 只不过,现在请求的阶段是http请求,然后建立连接,但是通信的阶段,确是双向读写,即基于TCP socket/websocket。
websocket
实际上,netty支持以下几个协议栈 1.http 2.H5的websocket
H5,当然也支持普通的http协议。
netty只是针对不同的http协议的数据体里的数据格式,比如,xml或json,需要借助第三方的开源软件。毕竟,不同的软件做专业的时候,与通信和通信协议相关的,netty都支持。至于具体的数据格式,能依赖第三方包就依赖第三方包。
http和websocket的区别? 实际上,没有任何区别。至少,从表面上看,没有什么区别。只是读写数据的时候一个是单向读写,一个是双向同时读写。
netty-拆包 粘包
发生的地方/情况
1.应用层数据比tcp socket缓冲区要大或小
大,拆包
小,粘包
2.tcp缓冲区比ip缓冲区要大或小
MSS
3.ip缓冲区比链路层要大或小
MTU
每一层的数据/缓冲区的大小是多少?
1.应用层
2.tcp
3.ip
MSS
是什么
最大段大小
作用
tcp到ip需要分节的大小
大小
MTS - (tcp首部+ip首部)
1000个字节 - 几十个字节 = 千位数字节
与SYN分节的关系
是SYN分节的一个选项?
本质?
MTU
是什么
最大传输单元
作用
Ip到链路层需要分节的大小
大小
1000个字节
本质?
发生的原因
在tcp层面
1.发送端的数据是流,流的意思是说,数据1和数据2是没有分界线的
2.接收端读数据的时候也是流,同样,也是不知道在哪里结束
也就是说,到目前为止,在tcp层面,还不能区分数据1和数据2。当然,tcp协议本来就不支持区分数据1和数据2,它把这个问题留给了上层的应用层程序自己去解决这个麻烦。分层的意义也在于此,就是每一层只做自己的那一部分工作,越简单越好,其他的都留给别人去做。
现在的解决方法,就是要在接收端,应用程序层要从tcp socket读缓冲区区分数据1和数据2。
拆包
一个数据拆分为多个包。接收端怎么知道多个包属于一个数据?每个数据有一个标识符唯一标识这个数据?没有唯一标识符。
不管是tcp分节,还是ip分节,每一层的协议都只负责当前协议层的数据(即分节)可靠到达目的地,然后,他们的使命就完成了。
至于,拆分为多个分节的数据,如何知道这些分节是属于同一个数据?这个不需要知道。因为tcp/ip已经把分节按发送顺序还原了,所以现在只需要确保找到不同数据的分隔符或长度就可以了。
综上所述,tcp ip报文/分节里,是没有当前分节属于哪一个数据的唯一标识符字段的!
粘包
同上。
解决方案有三种
1.固定长度
不管数据本身多大,发送时的数据规定为比如1000个字节,不够的话填充空白。
当然,此时,接受端读数据的时候,就每次读固定长度1000个字节即可。
那要是数据比1000个字节大呢?不能解决,或者要想其他办法解决。这个就是固定长度的缺点了。
2.以特殊字符比如换行符作为结束的标志
优点
缺点 数据本身可能包含特殊字符,这个问题需要单独处理掉。
例子
ftp
http
都有使用换行符作为结束标志
3.消息头+消息体
Tcp
Ip
http
都有分为消息头字段和消息体字段
绝大部分自定义协议,都是采用这种方法!
参考
华为专家写的书-李林峰
ip报文细节
待补充