netty小案例demo
阿新 • • 發佈:2019-02-20
Netty是業界最流行的NIO框架之一,它的健壯性、功能、效能、可定製性和可擴充套件性在同類框架中都是首屈一指的,它已經得到成百上千的商用專案驗證,例如Hadoop的RPC框架avro使用Netty作為底層通訊框架。很多其它業界主流的RPC框架,也使用Netty來構建高效能的非同步通訊能力。
通過對Netty的分析,我們將它的優點總結如下:
1) API使用簡單,開發門檻低;
2) 功能強大,預置了多種編解碼功能,支援多種主流協議;
3) 定製能力強,可以通過ChannelHandler對通訊框架進行靈活的擴充套件;
4) 效能高,通過與其它業界主流的NIO框架對比,Netty的綜合性能最優;
5) 成熟、穩定,Netty修復了已經發現的所有JDK NIO BUG,業務開發人員不需要再為NIO的BUG而煩惱;
6) 社群活躍,版本迭代週期短,發現的BUG可以被及時修復,同時,更多的新功能會被加入;
7) 經歷了大規模的商業應用考驗,質量已經得到驗證。在網際網路、大資料、網路遊戲、企業應用、電信軟體等眾多行業得到成功商用,證明了它可以完全滿足不同行業的商業應用。
正是因為這些優點,Netty逐漸成為Java NIO程式設計的首選框架。
接下來看一個demo
1、用到的jar
配置檔案 config.properties
#netty 服務端ip nioServerIp=127.0.0.1 #netty 服務端埠 nioServerPort=19990
2.服務段程式碼:
package netty.test; import java.io.InputStream; import java.util.Properties; /** properties檔案載入類 * @author xiefg * */ public class Configuration { private static Properties SYSTEM_CONFIG = new Properties(); public static String fileName = ""; private static final String PATH_SERVER_CONF = "netty/config/config.properties"; public static void init() { try { InputStream inputStream = null; ClassLoader classLoader = null; classLoader = Thread.currentThread().getContextClassLoader(); inputStream = classLoader.getResourceAsStream(PATH_SERVER_CONF); SYSTEM_CONFIG.load(inputStream); fileName = ""; int index = PATH_SERVER_CONF.lastIndexOf("/") == -1 ? PATH_SERVER_CONF .lastIndexOf("\\") : PATH_SERVER_CONF.lastIndexOf("/"); if (index > 0) { fileName = PATH_SERVER_CONF.substring(index + 1); } inputStream.close(); } catch (Exception e) { e.printStackTrace(); } return; } public static String getProperty(String key, String defaultValue) { try { return SYSTEM_CONFIG.getProperty(key, defaultValue); } catch (Exception e) { return null; } } public static String getProperty(String key) { try { String value = SYSTEM_CONFIG.getProperty(key); return value; } catch (Exception e) { return null; } } public static void main(String[] args) { init(); System.out.println(Configuration.getProperty("nioServerIp")); } }
package netty.test;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
/***
*
* @ClassName: NettyServer
* @Description: TODO netty 提供服務
* @author xiefg
* @date 2016年8月4日 下午5:02:05
*
*/
public class NettyServer {
//ip 地址
private static String IP = "127.0.0.1";
//預設埠
private static int PORT = 5656;
private static final int BIZGROUPSIZE = Runtime.getRuntime().availableProcessors()*2;
private static final int BIZTHREADSIZE = 100;
private static final EventLoopGroup bossGroup = new NioEventLoopGroup(BIZGROUPSIZE);
private static final EventLoopGroup workerGroup = new NioEventLoopGroup(BIZTHREADSIZE);
public static void init() throws Exception {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup);
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
// TODO Auto-generated method stub
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());
}
});
IP =Configuration.getProperty("nioServerIp");
PORT=Integer.parseInt(Configuration.getProperty("nioServerPort"));
System.out.println("【TCP伺服器IP】"+IP+"【TCP伺服器PORT】"+PORT);
ChannelFuture f = bootstrap.bind(IP, PORT).sync();
f.channel().closeFuture().sync();
System.out.println("TCP伺服器已啟動");
}
protected static void shutdown() {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
public static void main(String[] args) throws Exception {
System.out.println("初始化配置檔案...");
Configuration.init();
System.out.println("開始啟動TCP伺服器...");
NettyServer.init();
// HelloServer.shutdown();
}
}
package netty.test;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
/**
*
* @ClassName: ServerHandler
* @Description: TODO
* @author xiefg
* @date 2016年8月4日 下午5:34:19
*
*/
public class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
System.out.println("server receive message :"+ msg);
ctx.channel().writeAndFlush("yes server already accept your message" + msg);
ctx.close();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
System.out.println("【channelActive】。。。");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("【exception is general】");
}
}
3、客戶端程式碼
package netty.test;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
/**
*
* @ClassName: NettyClient
* @Description: TODO
* @author xiefg
* @date 2016年8月4日 下午5:46:43
*
*/
public class NettyClient implements Runnable {
@Override
public void run() {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group);
b.channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true);
b.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast("handler", new Client());
}
});
ChannelFuture f = b.connect("127.0.0.1", 19990).sync();
f.channel().writeAndFlush("Netty Hello Service!"+Thread.currentThread().getName()+":--->:"+Thread.currentThread().getId());
f.channel().closeFuture().sync();
} catch (Exception e) {
} finally {
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10; i++) {
new Thread(new NettyClient(),"【this thread】 "+i).start();
}
}
}
package netty.test;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
/**
*
* @ClassName: Client
* @Description: TODO
* @author xiefg
* @date 2016年8月4日 下午6:18:08
*
*/
public class Client extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("【client接收到伺服器返回的訊息】:" + msg);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("【client exception is general】");
}
}
啟動服務端如下圖:
服務端接收訊息如下圖