1.应用层和传输层以http协议为例。当我们访问一个网站时,浏览器会通过TCP协议向服务器的应用层发送如下字符串:GET/test/abtestHTTP/1.1Host:127.0.0.1Connection:keep-aliveCache-Control:max-age=0Upgrade-Insecure-Requests:1User-Agent:Mozilla/5.0(WindowsNT6.1;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/64.0.3282.186Safari/537.36Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8Accept-Encoding:gzip,deflate,brAccept-Language:zh-CN,zh;q=0.9,en;q=0.8Cookie:PHPSESSID=970260278652571648程序调试截图(tio的HttpRequest.toString())这些字符串是应用层数据,应用层数据是按照一定的格式组织的,这种格式就是应用层协议,比如http协议。传输层向应用层传输数据时,不保证每次传输的数据都是一个完整的应用层数据包(以http协议为例,不保证应用层接收到的数据一定是完整的应用层数据包)只是形成一个http包),这就是我们常说的半包和粘包。传输层只负责传输byte[]数据,应用层需要自己解码byte[]数据。以http协议为例,将byte[]解码成http协议格式的字符串。详情请参考:https://www.wanetech.com/doc/tio/802.ByteBuffer简介ByteBuffer是nio/aio编程必须掌握的数据结构,也是必须掌握的基础知识学会掌握技巧。想象一下,你不懂Map、List、Set,那么你在编程领域将一事无成。同理,不了解ByteBuffer,就无法在nio/aio编程领域立足。第一次知道ByteBuffer我们就可以理解bytebuffer是一个由以下属性组成的数据结构byte[]bytes:用于存储数据intcapacity:用于表示bytes的容量,那么可以想象capacity等于bytes.size(),这个值在字节初始化变化后不可用。intlimit:用来表示实际加载了多少字节的数据,很容易想象limit<=capacity,这个值是灵活多变的intposition:用来表示从哪个位置开始写入或读取数据到bytes,这个值是一个灵活的图片来感知ByteBuffer。详情请参考:https://www.wanetech.com/doc/tio/83创建ByteBufferByteBuffer.allocate(intcap)可以创建一个指定容器大小的ByteBuffer,看图往ByteBuffer中写入数据调用ByteBuffer.put(byteb)向ByteBuffer写入一个字节,如图从ByteBuffer中读取数据对于刚刚写入的bytebuffer,我们需要先设置它的位置,读取它的内容和limit,否则读取的位置不正确.接下来,调用ByteBuffer.get()来读取一个字节。在读取数据的同时,ByteBuffer的位置也会随之移动。见图3,HalfPacket和StickyPacket:正确的句子可以传达halfpackage顾名思义,收到halfapackage,此时还不足以形成应用层包。就像你想对喜欢的人说“我喜欢你”,但是因为喝了水,第一次只说了“我”,第二次说了“嗨”,第三次说了“嗨”.如果说“我喜欢你”,那就是半包问题。只有你说完这4个字,对方才知道你想说“我喜欢你”!以http协议为例,展示半包场景。粘包与半包相反。你可以一口气说出很多你想说的话。对方无法回应。你必须把你的话拆开,一个一个地理解。以http协议为例,展示粘包的场景:http协议是单向的,所以正常场景下不会有粘包,但是在pipeline模式下,允许一方连续发送多个请求,那么为什么会有粘包呢?无数刚接触网络编程的同学,往往认为每次收到的数据只是一个完整的数据包。所以当网络不好或者报文包太大的时候,会出现半包的情况,而程序没有考虑到半包的情况,结果就是解码失败,导致报文丢失。当通信方在一个TCP包中发送多个业务数据包时,会产生粘包,程序不考虑一次TCP接收。一个包会收到多个业务包,所以在解析完第一个业务包后,后面的业务包都会被丢弃。百度一下半包粘包,肯定会查到很多记录,也证明这两款货确实坑了无数人。那么看完这一段,你还会继续犯贴半包的错误吗?详情请参考:https://www.wanetech.com/doc/tio/84
