TCP粘包产生原因
- 应用程序write写入的字节数大小大于套接字发送缓冲区的大小。
- 进行MSS大小的TCP分段。
- 以太网帧的payload大于MTU进行IP分片。
用于解决TCP粘包问题的编码器
序号 | 名字 | 作用 |
---|---|---|
1 | LineBasedFrameDecoder | 基于 行 的解码器 |
2 | StringDecoder | 基于 字符串 的解码器 |
3 | DelimiterBasedFrameDecoder | 基于 分隔符 作为码流结束标示的消息解码器 |
4 | FixedLengthFrameDecoder | 基于 固定长度 解码器 |
LineBasedFrameDecoder – 基于 行 的解码器。遍历ByteBuf中的可读字节,判断是否有
"\n"
或"\r\n"
,如有则以此结束位置。可配置单行最大长度,如达到最大长度,仍没有发现换行符,则抛出异常。(见代码片段1)1
2
3
4
5
6
7
8
9
10
11// 代码片段1
public class TimeServer {
private class ChildChanneHandler extends ChannelInitiallizer<SocketChannel> {
protected void initChannel(SocketChannel arg0) throws Execption {
arg0.pipeline().addLast ( new LineBasedFrameDecoder(1024));
arg0.pipeline().addLast ( new StringDecoder());
arg0.pipeline().addLast ( new TimeClientHandler());
}
}
}StringDecoder – 基于 字符串 的解码器。将接收到的byte[]转换成字符串。LineBasedFrameDecoder+StringDecoder的组合即为按行切换的文本解码器。
DelimiterBasedFrameDecoder – 基于 分隔符 作为码流结束标示的消息解码器。(见代码片段2)
1
2
3
4
5
6
7
8
9
10
11
12
13// 代码片段2
public class EchoServer {
private class ChildChanneHandler extends ChannelInitiallizer<SocketChannel> {
protected void initChannel(SocketChannel arg0) throws Execption {
ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes()))
arg0.pipeline().addLast ( new DelimiterBasedFrameDecoder(1024,delimiter));
// arg0.pipeline().addLast ( new LineBasedFrameDecoder(1024));
arg0.pipeline().addLast ( new StringDecoder());
arg0.pipeline().addLast ( new TimeClientHandler());
}
}
}FixedLengthFrameDecoder – 固定长度 解码器.(见代码片段3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14// 代码片段3
public class EchoServer {
private class ChildChanneHandler extends ChannelInitiallizer<SocketChannel> {
protected void initChannel(SocketChannel arg0) throws Execption {
ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes()))
// arg0.pipeline().addLast ( new DelimiterBasedFrameDecoder(1024,delimiter));
// arg0.pipeline().addLast ( new LineBasedFrameDecoder(1024));
arg0.pipeline().addLast ( new FixedLengthFrameDecoder(20));
arg0.pipeline().addLast ( new StringDecoder());
arg0.pipeline().addLast ( new TimeClientHandler());
}
}
}