1.长连接:Client方与Server方先建立通讯连接,连接建立后不断开, 然后再进行报文发送和接收。长连接在 netty 中是默认开启的,也就是我们创建了一个 Server 以后监听端口,我们的客户端去连接发现只要我们的客户端不主动的断开连接他们之间的连接是一直保持有效的。 2.短连接:Client方与Server每进行一次报文收发交易时才进行通讯连接,交易完毕后立即断开连接。此种方式常用于一点对多点通讯,比如多个Client连接一个Server。但是在 netty 中默认采用了长连接,我们如何使用短连接呢?其实很简单,在我们的 Server 端需要对客户端进行回写数据的时候我们只需要在回写的后面加上一个监听事件,就是当写完毕,我们就关闭此连接。
ctx.channel().writeAndFlush("Hi Client I'm Server !&&").addListener(ChannelFutureListener.CLOSE);
1:如果利用tcp每次发送数据,就与对方建立连接,然后双方发送完一段数据后,就关闭连接,这样就不会出现粘包问题,因为只有一种包结构,类似于http协议。 2:如果发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储就ok,也不用考虑粘包 3:如果双方建立连接,需要在连接后一段时间内发送不同结构数据,则需要考虑粘包问题。
TCP 是一个字节流的的传输,也就是在流中传输无固定结构的数据包。但是UDP不会出现粘包,因为它有消息边界。 1 发送端需要等缓冲区满才发送出去,造成粘包 2 接收方不及时接收缓冲区的包,造成多个包接收
具体的在 TCP 中出现这种情况的原因:
以上提到的三种措施,都有其不足之处。第一种编程设置方法虽然可以避免发送方引起的粘包,但它关闭了优化算法,降低了网络发送效率,影响应用程序的性能,一般不建议使用。第二种方法只能减少出现粘包的可能性,但并不能完全避免粘包,当发送频率较高时,或由于网络突发可能使某个时间段数据包到达接收方较快,接收方还是有可能来不及接收,从而导致粘包。第三种方法虽然避免了粘包,但应用程序的效率较低,对实时应用的场合不适合。
最初遇到”粘包”的问题时,我是通过在两次send之间调用sleep来休眠一小段时间来解决.这个解决方法的缺点是显而易见的,使传输效率大大降低,而且也并不可靠.后来就是通过应答的方式来解决,尽管在大多数时候是可行的,但是不能解决象B的那种情况,而且采用应答方式增加了通讯量,加重了网络负荷. 再后来就是对数据包进行封包和拆包的操作. 封包:封包就是给一段数据加上包头,这样一来数据包就分为包头和包体两部分内容了(以后讲过滤非法包时封包会加入”包尾”内容).包头其实上是个大小固定的结构体,其中有个结构体成员变量表示包体的长度,这是个很重要的变量,其他的结构体成员可根据需要自己定义.根据包头长度固定以及包头中含有包体长度的变量就能正确的拆分出一个完整的数据包.
DelimiterBasedFrameDecoder(arg0,agr1)
其中第一个参数指的是这个分隔符的可占用的空间大小,只能比他大不能小于。第二个参数就是具体的分隔符了,但是不能传递一个字符串而是一个 ByteBuf
对象,也就是我们需要用工具转一下 Unpooled.copiedBuffer("&&".getBytes())
,代码如下:pipeline.addLast(new DelimiterBasedFrameDecoder(1024, Unpooled.copiedBuffer("&&".getBytes())));
.addLast(new FixedLengthFrameDecoder(5));
参考资料: