Netty入门官方例子
學(xué)習(xí)分布式,正好看到Netty 是一個基于NIO的客戶、服務(wù)器端編程框架,所以本著學(xué)習(xí)的態(tài)度去官網(wǎng)看了一下,官網(wǎng)例子,本著以后可以翻出來再看看的心態(tài),把官網(wǎng)的第一個例子貼出來,也希望自己以后有一個可以復(fù)習(xí)的地方,第一次使用博客功能,還有很多不懂的地方
一.jar包
<!-- Netty開始 -->
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
? ?<groupId>io.netty</groupId>
? ?<artifactId>netty-all</artifactId>
? ?<version>4.1.6.Final</version>
</dependency>
<!-- Netty結(jié)束 -->
二.DEMO
官方并沒有使用Hello World來作為一個例子,而是采用RFC的DISCARD,這個協(xié)議定義了就是接收到請求后什么也不干。
第一步編寫DiscardServerHandler類:
package io.netty.example.discard;
?
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
//ChannelInboundHandlerAdapter實現(xiàn)自ChannelInboundHandler
//ChannelInboundHandler提供了不同的事件處理方法你可以重寫
public class DiscardServerHandler extends ChannelInboundHandlerAdapter {
?? ?/*?
?? ? * @作者:CJY
?? ? * @說明:該方法用于接收從客戶端接收的信息
?? ? * @時間:2017-4-2下午12:25:05
?? ? * @see io.netty.channel.ChannelInboundHandlerAdapter#channelRead(io.netty.channel.ChannelHandlerContext, java.lang.Object)
?? ? * @param ctx
?? ? * @param msg
?? ? * @throws Exception
?? ? */
?? ?@Override
?? ?public void channelRead(ChannelHandlerContext ctx, Object msg)
?? ??? ??? ?throws Exception {
?? ??? ?//Discard the received data silently
?? ??? ?//ByteBuf是一個引用計數(shù)對象實現(xiàn)ReferenceCounted,他就是在有對象引用的時候計數(shù)+1,無的時候計數(shù)-1,當(dāng)為0對象釋放內(nèi)存
?? ??? ?ByteBuf in=(ByteBuf)msg;
?? ??? ?try {
?? ??? ??? ?while(in.isReadable()){
?? ??? ??? ??? ?System.out.println((char)in.readByte());
?? ??? ??? ??? ?System.out.flush();
?? ??? ??? ?}
?? ??? ?} finally {
?? ??? ??? ?ReferenceCountUtil.release(msg);
?? ??? ?}
?? ?}
?? ?
?? ?@Override
?? ?public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
?? ??? ??? ?throws Exception {
?? ??? ?cause.printStackTrace();
?? ??? ?ctx.close();
?? ?}
}
第二步編寫DiscardServer:
package io.netty.example.discard;
?
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
?
public class DiscardServer {
?? ?private int port;
?? ?public DiscardServer(int port){
?? ??? ?this.port = port;
?? ?}
?? ?
?? ?public void run() throws Exception{
?? ??? ?//Group:群組,Loop:循環(huán),Event:事件,這幾個東西聯(lián)在一起,相比大家也大概明白它的用途了。
?? ??? ?//Netty內(nèi)部都是通過線程在處理各種數(shù)據(jù),EventLoopGroup就是用來管理調(diào)度他們的,注冊Channel,管理他們的生命周期。
?? ??? ?//NioEventLoopGroup是一個處理I/O操作的多線程事件循環(huán)
?? ??? ?//bossGroup作為boss,接收傳入連接
?? ??? ?//因為bossGroup僅接收客戶端連接,不做復(fù)雜的邏輯處理,為了盡可能減少資源的占用,取值越小越好
?? ??? ?EventLoopGroup bossGroup=new NioEventLoopGroup(1);
?? ??? ?//workerGroup作為worker,處理boss接收的連接的流量和將接收的連接注冊進入這個worker
?? ??? ?EventLoopGroup workerGroup=new NioEventLoopGroup();
?? ??? ?try {
?? ??? ??? ?//ServerBootstrap負(fù)責(zé)建立服務(wù)端
?? ??? ??? ?//你可以直接使用Channel去建立服務(wù)端,但是大多數(shù)情況下你無需做這種乏味的事情
?? ??? ??? ?ServerBootstrap b=new ServerBootstrap();
?? ??? ??? ?b.group(bossGroup, workerGroup)
?? ??? ??? ?//指定使用NioServerSocketChannel產(chǎn)生一個Channel用來接收連接
?? ??? ??? ?.channel(NioServerSocketChannel.class)
?? ??? ??? ?//ChannelInitializer用于配置一個新的Channel
?? ??? ??? ?//用于向你的Channel當(dāng)中添加ChannelInboundHandler的實現(xiàn)
?? ??? ??? ?.childHandler(new ChannelInitializer<SocketChannel>() {
?? ??? ??? ??? ?public void initChannel(SocketChannel ch) throws Exception {
?? ??? ??? ??? ??? ?//ChannelPipeline用于存放管理ChannelHandel
?? ??? ??? ??? ??? ?//ChannelHandler用于處理請求響應(yīng)的業(yè)務(wù)邏輯相關(guān)代碼
?? ??? ??? ??? ??? ?ch.pipeline().addLast(new DiscardServerHandler());
?? ??? ??? ??? ?};
?? ??? ??? ?})
?? ??? ??? ?//對Channel進行一些配置
?? ??? ??? ?//注意以下是socket的標(biāo)準(zhǔn)參數(shù)
?? ??? ??? ?//BACKLOG用于構(gòu)造服務(wù)端套接字ServerSocket對象,標(biāo)識當(dāng)服務(wù)器請求處理線程全滿時,用于臨時存放已完成三次握手的請求的隊列的最大長度。如果未設(shè)置或所設(shè)置的值小于1,Java將使用默認(rèn)值50。
?? ??? ??? ?//Option是為了NioServerSocketChannel設(shè)置的,用來接收傳入連接的
?? ??? ??? ?.option(ChannelOption.SO_BACKLOG, 128)
?? ??? ??? ?//是否啟用心跳?;顧C制。在雙方TCP套接字建立連接后(即都進入ESTABLISHED狀態(tài))并且在兩個小時左右上層沒有任何數(shù)據(jù)傳輸?shù)那闆r下,這套機制才會被激活。
?? ??? ??? ?//childOption是用來給父級ServerChannel之下的Channels設(shè)置參數(shù)的
?? ??? ??? ?.childOption(ChannelOption.SO_KEEPALIVE, true);
?? ??? ??? ?// Bind and start to accept incoming connections.
?? ??? ??? ?ChannelFuture f=b.bind(port).sync();
?? ??? ??? ?// Wait until the server socket is closed.
? ? ? ? ? ? // In this example, this does not happen, but you can do that to gracefully
? ? ? ? ? ? // shut down your server.
?? ??? ??? ?//sync()會同步等待連接操作結(jié)果,用戶線程將在此wait(),直到連接操作完成之后,線程被notify(),用戶代碼繼續(xù)執(zhí)行
?? ??? ??? ?//closeFuture()當(dāng)Channel關(guān)閉時返回一個ChannelFuture,用于鏈路檢測
? ? ? ? ? ? f.channel().closeFuture().sync();
?? ??? ?}finally{
?? ??? ??? ?//資源優(yōu)雅釋放
?? ??? ??? ?bossGroup.shutdownGracefully();
?? ??? ??? ?workerGroup.shutdownGracefully();
?? ??? ?}
?? ?}
?? ?
?? ?public static void main(String[] args) {
?? ??? ?int port=8088;
?? ??? ?try {
?? ??? ??? ?new DiscardServer(port).run();
?? ??? ?} catch (Exception e) {
?? ??? ??? ?// TODO Auto-generated catch block
?? ??? ??? ?e.printStackTrace();
?? ??? ?}
?? ?}
}
里面的具體的類在注釋當(dāng)中進行了說明這里就不在一個一個羅列了,目前也是在初步學(xué)習(xí)階段,所以如果有不對的也希望大神指正。
三.測試
打開Window的命令行,輸入telnet命令:telnet localhost 8088,如果能夠正確連接就代表成功,在新打開的命令窗口隨意輸入字符,如果在myeclipse當(dāng)中能夠正確輸出在console當(dāng)中,就代表程序正常。
四.ECHO協(xié)議的DEMO
ECHO協(xié)議,定義了客戶端請求啥就返回啥
第一步編寫EchoServerHandler:
package io.netty.example.echo;
?
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
?
/**
?* @作者:CJY
?* @說明:這個是用來實現(xiàn)ECHO協(xié)議,這個協(xié)議的作用就是將客戶端輸入的信息全部返回
?* @時間:2017-4-8下午12:07:50
?*/
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
?? ?/*?
?? ? * @作者:CJY
?? ? * @說明:該方法用于接收從客戶端接收的信息
?? ? * @時間:2017-4-8下午12:08:51
?? ? * @see io.netty.channel.ChannelInboundHandlerAdapter#channelRead(io.netty.channel.ChannelHandlerContext, java.lang.Object)
?? ? * @param ctx
?? ? * @param msg
?? ? * @throws Exception
?? ? */
?? ?@Override
?? ?public void channelRead(ChannelHandlerContext ctx, Object msg)
?? ??? ??? ?throws Exception {
?? ??? ?//ChannelHandlerContext提供各種不同的操作用于觸發(fā)不同的I/O時間和操作
?? ??? ?//調(diào)用write方法來逐字返回接收到的信息
?? ??? ?//這里我們不需要在DISCARD例子當(dāng)中那樣調(diào)用釋放,因為Netty會在寫的時候自動釋放
?? ??? ?//只調(diào)用write是不會釋放的,它會緩存,直到調(diào)用flush
?? ??? ?ctx.write(msg);
?? ??? ?ctx.flush();
?? ??? ?//你可以直接使用writeAndFlush(msg)
?? ??? ?//ctx.writeAndFlush(msg);
?? ?}
?? ?
?? ?@Override
?? ?public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
?? ??? ??? ?throws Exception {
?? ??? ?cause.printStackTrace();
?? ??? ?ctx.close();
?? ?}
}
第二步編寫EchoServer:
package io.netty.example.echo;
?
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
?
public class EchoServer {
?? ?private int port;
?? ?public EchoServer(int port){
?? ??? ?this.port = port;
?? ?}
?? ?
?? ?public void run() throws Exception{
?? ??? ?//NioEventLoopGroup是一個處理I/O操作的多線程事件循環(huán)
?? ??? ?//bossGroup作為boss,接收傳入連接
?? ??? ?//bossGroup只負(fù)責(zé)接收客戶端的連接,不做復(fù)雜操作,為了減少資源占用,取值越小越好
?? ??? ?//Group:群組,Loop:循環(huán),Event:事件,這幾個東西聯(lián)在一起,相比大家也大概明白它的用途了。
?? ??? ?//Netty內(nèi)部都是通過線程在處理各種數(shù)據(jù),EventLoopGroup就是用來管理調(diào)度他們的,注冊Channel,管理他們的生命周期。
?? ??? ?EventLoopGroup bossGroup=new NioEventLoopGroup(1);
?? ??? ?//workerGroup作為worker,處理boss接收的連接的流量和將接收的連接注冊進入這個worker
?? ??? ?EventLoopGroup workerGroup=new NioEventLoopGroup();
?? ??? ?try {
?? ??? ??? ?//ServerBootstrap負(fù)責(zé)建立服務(wù)端
?? ??? ??? ?//你可以直接使用Channel去建立服務(wù)端,但是大多數(shù)情況下你無需做這種乏味的事情
?? ??? ??? ?ServerBootstrap b=new ServerBootstrap();
?? ??? ??? ?b.group(bossGroup, workerGroup)
?? ??? ??? ?//指定使用NioServerSocketChannel產(chǎn)生一個Channel用來接收連接
?? ??? ??? ?.channel(NioServerSocketChannel.class)
?? ??? ??? ?//ChannelInitializer用于配置一個新的Channel
?? ??? ??? ?//用于向你的Channel當(dāng)中添加ChannelInboundHandler的實現(xiàn)
?? ??? ??? ?.childHandler(new ChannelInitializer<SocketChannel>() {
?? ??? ??? ??? ?public void initChannel(SocketChannel ch) throws Exception {
?? ??? ??? ??? ??? ?ch.pipeline().addLast(new EchoServerHandler());
?? ??? ??? ??? ?};
?? ??? ??? ?})
?? ??? ??? ?//對Channel進行一些配置
?? ??? ??? ?//注意以下是socket的標(biāo)準(zhǔn)參數(shù)
?? ??? ??? ?//BACKLOG用于構(gòu)造服務(wù)端套接字ServerSocket對象,標(biāo)識當(dāng)服務(wù)器請求處理線程全滿時,用于臨時存放已完成三次握手的請求的隊列的最大長度。如果未設(shè)置或所設(shè)置的值小于1,Java將使用默認(rèn)值50。
?? ??? ??? ?//Option是為了NioServerSocketChannel設(shè)置的,用來接收傳入連接的
?? ??? ??? ?.option(ChannelOption.SO_BACKLOG, 128)
?? ??? ??? ?//是否啟用心跳保活機制。在雙方TCP套接字建立連接后(即都進入ESTABLISHED狀態(tài))并且在兩個小時左右上層沒有任何數(shù)據(jù)傳輸?shù)那闆r下,這套機制才會被激活。
?? ??? ??? ?//childOption是用來給父級ServerChannel之下的Channels設(shè)置參數(shù)的
?? ??? ??? ?.childOption(ChannelOption.SO_KEEPALIVE, true);
?? ??? ??? ?// Bind and start to accept incoming connections.
?? ??? ??? ?ChannelFuture f=b.bind(port).sync();
?? ??? ??? ?// Wait until the server socket is closed.
? ? ? ? ? ? // In this example, this does not happen, but you can do that to gracefully
? ? ? ? ? ? // shut down your server.
?? ??? ??? ?//sync()會同步等待連接操作結(jié)果,用戶線程將在此wait(),直到連接操作完成之后,線程被notify(),用戶代碼繼續(xù)執(zhí)行
?? ??? ??? ?//closeFuture()當(dāng)Channel關(guān)閉時返回一個ChannelFuture,用于鏈路檢測
? ? ? ? ? ? f.channel().closeFuture().sync();
?? ??? ?}finally{
?? ??? ??? ?//資源優(yōu)雅釋放
?? ??? ??? ?bossGroup.shutdownGracefully();
?? ??? ??? ?workerGroup.shutdownGracefully();
?? ??? ?}
?? ?}
?? ?
?? ?public static void main(String[] args) {
?? ??? ?int port=8088;
?? ??? ?try {
?? ??? ??? ?new EchoServer(port).run();
?? ??? ?} catch (Exception e) {
?? ??? ??? ?// TODO Auto-generated catch block
?? ??? ??? ?e.printStackTrace();
?? ??? ?}
?? ?}
}
測試如上
---------------------?
作者:wocjy?
來源:CSDN?
原文:https://blog.csdn.net/wocjy/article/details/78661464?
版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請附上博文鏈接!
總結(jié)
以上是生活随笔為你收集整理的Netty入门官方例子的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Netty框架入门
- 下一篇: 关于Netty的入门使用