netty 支持socket通信
- 1,netty 大大簡化了socket開發(fā),提高了socket的性能。
- 2,Netty提供異步的、事件驅動的網絡應用程序框架和工具,
用以快速開發(fā)高性能、高可靠性的網絡服務器和客戶端程序。
系列文章
[netty 基本使用- 作為http服務器][gcssloop]
[gcssloop]: http://www.lxweimin.com/p/cd88723c96dc
服務器端代碼
ServerSocket.java
public class ServerSocket {
public static void main(String ...arg) throws Exception {
//負責接收客戶端連接
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
//負責處理連接
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();
//數據分包,組包,粘包
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è)務 **
public class ServerHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
//接收到的數據
System.out.println(ctx.channel().remoteAddress()+" , "+msg);
//返回給客戶端的數據
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();
//數據分包,組包,粘包
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è)務 **
public class ClientHandler extends SimpleChannelInboundHandler<String> {
//接收服務端數據&發(fā)送數據
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("客戶端接收到的消息: "+msg);
ctx.writeAndFlush(LocalDateTime.now());
//完成通信后關閉連接
//ctx.close();
}
//和服務器建立連接
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush("在嗎?。。?!");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
** 可以多次和服務器端通信的寫法 **
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();
//接收輸入的數據
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 常用的處理大數據分包傳輸問題的解決類。
- maxFrameLength:解碼的幀的最大長度。
- lengthFieldOffset: 長度屬性的起始位(偏移位),包中存放有整個大數據包長度的字節(jié),這段字節(jié)的其實位置。
- lengthFieldLength:長度屬性的長度,即存放整個大數據包長度的字節(jié)所占的長度。
- lengthAdjustmen:長度調節(jié)值,在總長被定義為包含包頭長度時,修正信息長度。
- initialBytesToStrip:跳過的字節(jié)數,根據需要我們跳過lengthFieldLength個字節(jié),以便接收端直接接受到不含“長度屬性”的內容。
LengthFieldPrepender 編碼類
編碼類,自動將
+----------------+
| "HELLO, WORLD" |
+----------------+
格式的數據轉換成
+--------+----------------+
- 0x000C | "HELLO, WORLD" |
+--------+----------------+
格式的數據
參考文章
[netty 數據分包、組包、粘包處理機制][123]
[123]: http://blog.163.com/linfenliang@126/blog/static/127857195201210821145721/