在tcp编程底层都有拆包和粘包的机制
拆包
当发送数据量过大时数据量会分多次发送
以前面helloWord代码为例
package com.liqiang.nettyTest2; public class nettyMain {
public static void main(String[] args) {
new Thread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
Server server = new Server(8081);
server.start();
}
}).start();
new Thread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
Client client1=new Client("127.0.0.1", 8081);
client1.connection();
client1.sendMsg("In this chapter you general, we recommend Java Concurrency in Practice by Brian Goetz. His book w"
+ "ill give We’ve reached an exciting point—in the next chapter we’ll discuss bootstrapping, the process "
+ "of configuring and connecting all of Netty’s components to bring your learned about threading models in ge"
+ "neral and Netty’s threading model in particular, whose performance and consistency advantages we discuss"
+ "ed in detail In this chapter you general, we recommend Java Concurrency in Practice by Brian Goetz. Hi"
+ "s book will give We’ve reached an exciting point—in the next chapter we’ll discuss bootstrapping, the"
+ " process of configuring and connecting all of Netty’s components to bring your learned about threading "
+ "models in general and Netty’s threading model in particular, whose performance and consistency advantag"
+ "es we discussed in detailIn this chapter you general, we recommend Java Concurrency in Practice by Bri"
+ "an Goetz. His book will give We’ve reached an exciting point—in the next chapter;the counter is: 1 2222"
+ "sdsa ddasd asdsadas dsadasdas");
}
}).start();
}
}
打印
可以发现这里拆分成了2次发送
粘包
当发送数据量过小时会组合成一次发送
package com.liqiang.nettyTest2; public class nettyMain {
public static void main(String[] args) {
new Thread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
Server server = new Server(8081);
server.start();
}
}).start();
new Thread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
Client client1=new Client("127.0.0.1", 8081);
client1.connection();
for(int i=0;i<100;i++) {
client1.sendMsg("d");
} }
}).start();
}
}
可以发现有时多条发送的数据会组合成一条发送
解决方案
netty提供了解码器来解决拆包和粘包的问题
LineBasedFrameDecoder
通过换行符来区分包
服务器端增加LineBasedFrameDecoder
package com.liqiang.nettyTest2; import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.AsciiHeadersEncoder.NewlineType;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder; public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> { private Server server;
public ServerChannelInitializer(Server server) {
this.server=server;
}
@Override
protected void initChannel(SocketChannel channel) throws Exception {
// TODO Auto-generated method stub
channel.pipeline()
.addLast(new LineBasedFrameDecoder(2048))//2048是限制一个包的最大字节数。如果超过将会报异常
.addLast("decoder",new StringDecoder())//接收到数据 自动将将buffer转换为String 避免自己再转
.addLast("encoder",new StringEncoder())//发送数据 可以直接发送String 框架内部转换为buffer传输
.addLast(new ServerHandle(server));
} }
客户端
package com.liqiang.nettyTest2; public class nettyMain {
public static void main(String[] args) {
new Thread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
Server server = new Server(8081);
server.start(); }
}).start();
new Thread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
Client client1=new Client("127.0.0.1", 8081);
client1.connection();
client1.sendMsg("In this chapter you general, we recommend Java Concurrency in Practice by Brian Goetz. His book w"
+ "ill give We’ve reached an exciting point—in the next chapter we’ll discuss bootstrapping, the process "
+ "of configuring and connecting all of Netty’s components to bring your learned about threading models in ge"
+ "neral and Netty’s threading model in particular, whose performance and consistency advantages we discuss"
+ "ed in detail In this chapter you general, we recommend Java Concurrency in Practice by Brian Goetz. Hi"
+ "s book will give We’ve reached an exciting point—in the next chapter we’ll discuss bootstrapping, the"
+ " process of configuring and connecting all of Netty’s components to bring your learned about threading "
+ "models in general and Netty’s threading model in particular, whose performance and consistency advantag"
+ "es we discussed in detailIn this chapter you general, we recommend Java Concurrency in Practice by Bri"
+ "an Goetz. His book will give We’ve reached an exciting point—in the next chapter;the counter is: 1 2222"
+ "sdsa ddasd asdsadas dsadasdas"+System.getProperty("line.separator"));//System.getProperty("line.separator") 兼容linux和windows换行符的区别
}
}).start();
}
}
如果发送数据忘记拼换行符 服务器将不会有任何打印
DelimiterBasedFrameDecoder
通过指定符号区分
服务器端
package com.liqiang.nettyTest2; import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.AsciiHeadersEncoder.NewlineType;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder; public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> { private Server server;
public ServerChannelInitializer(Server server) {
this.server=server;
}
@Override
protected void initChannel(SocketChannel channel) throws Exception {
// TODO Auto-generated method stub
channel.pipeline()
.addLast(new DelimiterBasedFrameDecoder(2048,Unpooled.copiedBuffer("$$__".getBytes())))//$__为包的分隔符2048是限制一个包的最大字节数。如果超过将会报异常
.addLast("decoder",new StringDecoder())//接收到数据 自动将将buffer转换为String 避免自己再转
.addLast("encoder",new StringEncoder())//发送数据 可以直接发送String 框架内部转换为buffer传输
.addLast(new ServerHandle(server));
} }
客户端
package com.liqiang.nettyTest2; public class nettyMain {
public static void main(String[] args) {
new Thread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
Server server = new Server(8081);
server.start(); }
}).start();
new Thread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
Client client1=new Client("127.0.0.1", 8081);
client1.connection();
client1.sendMsg("In this chapter you general, we recommend Java Concurrency in Practice by Brian Goetz. His book w"
+ "ill give We’ve reached an exciting point—in the next chapter we’ll discuss bootstrapping, the process "
+ "of configuring and connecting all of Netty’s components to bring your learned about threading models in ge"
+ "neral and Netty’s threading model in $$__particular, whose performance and consistency advantages we discuss"
+ "ed in detail In this chapter you general, we recommend Java Concurrency in Practice by Brian Goetz. Hi"
+ "s book will give We’ve reached an exciting point—in the next chapter we’ll discuss bootstrapping, the"
+ " process of configuring and connecting all $$__of Netty’s components to bring your learned about threading "
+ "models in general and Netty’s threading model in particular, whose performance and consistency advantag"
+ "es we discussed in detailIn this chapter you general, we recommend Java Concurrency in Practice by Bri"
+ "an Goetz. His book will give We’ve reached an exciting point—in the next chapter;the counter is: 1 2222"
+ "sdsa ddasd asdsadas dsadasdas$__");
}
}).start();
}
}
根据$__数据被拆分成了三个包