netty 支持socket通信
- 1安吁,netty 大大簡化了socket開發(fā),提高了socket的性能睛琳。
- 2盒蟆,Netty提供異步的、事件驅(qū)動的網(wǎng)絡(luò)應(yīng)用程序框架和工具师骗,
用以快速開發(fā)高性能历等、高可靠性的網(wǎng)絡(luò)服務(wù)器和客戶端程序。
系列文章
[netty 基本使用- 作為http服務(wù)器][gcssloop]
[gcssloop]: http://www.reibang.com/p/cd88723c96dc
服務(wù)器端代碼
ServerSocket.java
public class ServerSocket {
public static void main(String ...arg) throws Exception {
//負(fù)責(zé)接收客戶端連接
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
//負(fù)責(zé)處理連接
NioEventLoopGroup wokerGroup = new NioEventLoopGroup();
try{
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup,wokerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ServerInitializer());
//綁定端口號
ChannelFuture channelFuture = bootstrap.bind(9999).sync();
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
wokerGroup.shutdownGracefully();
}
}
}
** ServerInitializer.java **
public class ServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//數(shù)據(jù)分包辟癌,組包寒屯,粘包
pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new ServerHandler());
}
}
** ServerHandler.java 處理業(yè)務(wù) **
public class ServerHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
//接收到的數(shù)據(jù)
System.out.println(ctx.channel().remoteAddress()+" , "+msg);
//返回給客戶端的數(shù)據(jù)
ctx.channel().writeAndFlush("server: "+ UUID.randomUUID());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
客戶端端代碼
** ClientSocket.java **
public class ClientSocket {
public static void main(String[] arg) throws Exception {
NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
.handler(new Clientinitializer());
ChannelFuture channelFuture = bootstrap.connect("localhost", 9999).sync();
channelFuture.channel().closeFuture().sync();
} finally {
eventLoopGroup.shutdownGracefully();
}
}
}
** Clientinitializer.java **
public class Clientinitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//數(shù)據(jù)分包,組包黍少,粘包
pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new ClientHandler());
}
}
**ClientHandler.java 處理業(yè)務(wù) **
public class ClientHandler extends SimpleChannelInboundHandler<String> {
//接收服務(wù)端數(shù)據(jù)&發(fā)送數(shù)據(jù)
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("客戶端接收到的消息: "+msg);
ctx.writeAndFlush(LocalDateTime.now());
//完成通信后關(guān)閉連接
//ctx.close();
}
//和服務(wù)器建立連接
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush("在嗎9鸭小!3е谩菩掏!");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
** 可以多次和服務(wù)器端通信的寫法 **
public class ClientSocket2 {
public static void main(String[] arg) throws Exception {
NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
.handler(new Clientinitializer());
ChannelFuture channelFuture = bootstrap.connect("localhost", 9999).sync();
Channel channel = channelFuture.channel();
//接收輸入的數(shù)據(jù)
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in, CharsetUtil.UTF_8));
while (true) {
String sendMsg = bufferedReader.readLine() ;
if ("esc".equals(sendMsg)) {
channel.close();
break;
}
sendMsg += "\r\n";
channel.writeAndFlush(sendMsg);
}
} finally {
eventLoopGroup.shutdownGracefully();
}
}
}
LengthFieldBasedFrameDecoder
netty 常用的處理大數(shù)據(jù)分包傳輸問題的解決類。
- maxFrameLength:解碼的幀的最大長度昵济。
- lengthFieldOffset: 長度屬性的起始位(偏移位)智绸,包中存放有整個(gè)大數(shù)據(jù)包長度的字節(jié),這段字節(jié)的其實(shí)位置访忿。
- lengthFieldLength:長度屬性的長度瞧栗,即存放整個(gè)大數(shù)據(jù)包長度的字節(jié)所占的長度。
- lengthAdjustmen:長度調(diào)節(jié)值醉顽,在總長被定義為包含包頭長度時(shí)沼溜,修正信息長度平挑。
- initialBytesToStrip:跳過的字節(jié)數(shù)游添,根據(jù)需要我們跳過lengthFieldLength個(gè)字節(jié)系草,以便接收端直接接受到不含“長度屬性”的內(nèi)容。
LengthFieldPrepender 編碼類
編碼類唆涝,自動將
+----------------+
| "HELLO, WORLD" |
+----------------+
格式的數(shù)據(jù)轉(zhuǎn)換成
+--------+----------------+
- 0x000C | "HELLO, WORLD" |
+--------+----------------+
格式的數(shù)據(jù)
參考文章
[netty 數(shù)據(jù)分包找都、組包、粘包處理機(jī)制][123]
[123]: http://blog.163.com/linfenliang@126/blog/static/127857195201210821145721/