您的位置:首页 > 其它

netty 学习 (1)

2016-07-02 18:40 295 查看
摘要
本文是学习Netty的第一篇文章,主要对Netty的Server和Client间的通讯机制进行验证。

Server与Client建立连接后,会执行以下的步骤: 

1、Client向Server发送消息:Are you ok? 

2、Server接收客户端发送的消息,并打印出来。 

3、Server端向客户端发送消息:I am ok! 

4、Client接收Server端发送的消息,并打印出来,通讯结束。 

涉及到的类有4个: 

1、HelloServer :server类,启动Netty server 

2、HelloServerInHandler:server的handler,接收客户端消息,并向客户端发送消息 

3、HelloClient:client类,建立于Netty server的连接 
4、HelloClientIntHandler:client的handler,接收server端的消息,并向服务端发送消息

一、先加入必要的类库:



二、HelloServer代码如下:

package com.yao.netty;
 
importio.netty.bootstrap.ServerBootstrap;
importio.netty.channel.ChannelFuture;
importio.netty.channel.ChannelInitializer;
importio.netty.channel.ChannelOption;
importio.netty.channel.EventLoopGroup;
importio.netty.channel.nio.NioEventLoopGroup;
importio.netty.channel.socket.SocketChannel;
importio.netty.channel.socket.nio.NioServerSocketChannel;
 
publicclassHelloServer {
    publicvoidstart(int
port) throws Exception {
        EventLoopGroup bossGroup =
new NioEventLoopGroup();
        EventLoopGroup workerGroup =
new NioEventLoopGroup();
        try {
            ServerBootstrap b =
new ServerBootstrap();
            b.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class)
                    .childHandler(newChannelInitializer<SocketChannel>() {
                        @Override
                       
publicvoidinitChannel(SocketChannel ch)
                               
throws Exception {
                           
// 注册handler
                            ch.pipeline().addLast(newHelloServerInHandler());
                        }
                   }).option(ChannelOption.SO_BACKLOG,
128)
                   .childOption(ChannelOption.SO_KEEPALIVE,
true);
 
            ChannelFuture f =b.bind(port).sync();
 
            f.channel().closeFuture().sync();
        }
finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
 
    publicstaticvoidmain(String[]
args) throws Exception {
        HelloServer server =
new HelloServer();
        server.start(8000);
    }
}
三、 HelloServerInHandler代码如下: 

package com.yao.netty;
 
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
 
importorg.apache.commons.logging.Log;
importorg.apache.commons.logging.LogFactory;
 
// 该handler是InboundHandler类型
public class HelloServerInHandlerextends ChannelInboundHandlerAdapter {
    private
static Log logger = LogFactory.getLog(HelloServerInHandler.class);
 
    @Override
    public void channelRead(ChannelHandlerContextctx, Object msg)
            throws Exception {
        logger.info("HelloServerInHandler.channelRead");
        ByteBuf result = (ByteBuf) msg;
        byte[] result1 = new byte[result.readableBytes()];
        // msg中存储的是ByteBuf类型的数据,把数据读取到byte[]中
        result.readBytes(result1);
        String resultStr = new String(result1);
        //
接收并打印客户端的信息
        System.out.println("Client
said:" + resultStr);
        //
释放资源,这行很关键
        result.release();
 
        //
向客户端发送消息
        String response =
"I am ok!";
        //
在当前场景下,发送的数据必须转换成ByteBuf数组
        ByteBuf encoded = ctx.alloc().buffer(4 * response.length());
        encoded.writeBytes(response.getBytes());
        ctx.write(encoded);
        ctx.flush();
    }
 
    @Override
    public void channelReadComplete(ChannelHandlerContextctx) throws Exception {
        ctx.flush();
    }
}
四、HelloClient代码如下:

package com.yao.netty;
 
importio.netty.bootstrap.Bootstrap;
importio.netty.channel.ChannelFuture;
importio.netty.channel.ChannelInitializer;
importio.netty.channel.ChannelOption;
importio.netty.channel.EventLoopGroup;
importio.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
importio.netty.channel.socket.nio.NioSocketChannel;
 
publicclassHelloClient {
    publicvoidconnect(String
host, int port)
throws Exception {
        EventLoopGroup workerGroup =
new NioEventLoopGroup();
 
        try {
            Bootstrap b =
new Bootstrap();
           b.group(workerGroup).channel(NioSocketChannel.class).option(ChannelOption.SO_KEEPALIVE,true)
            .handler(newChannelInitializer<SocketChannel>()
{
                @Override
                publicvoidinitChannel(SocketChannel
ch) throws Exception {
                    ch.pipeline().addLast(newHelloClientIntHandler());
                }
            });
 
           
// Start the client.
            ChannelFuture f = b.connect(host,port).sync();
 
           
// Wait until the connection isclosed.
            f.channel().closeFuture().sync();
        }
finally {
            workerGroup.shutdownGracefully();
        }
 
    }
 
    publicstaticvoidmain(String[]
args) throws Exception {
        HelloClient client =
new HelloClient();
        client.connect("127.0.0.1",
8000);
    }
}
五、 HelloClientIntHandler代码如下:
package com.yao.netty;
 
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
 
importorg.apache.commons.logging.Log;
importorg.apache.commons.logging.LogFactory;
 
 
public class HelloClientIntHandlerextends ChannelInboundHandlerAdapter {
    private
static Log logger = LogFactory.getLog(HelloClientIntHandler.class);
 
    // 接收server端的消息,并打印出来
    @Override
    public void channelRead(ChannelHandlerContextctx, Object msg) throws Exception {
        logger.info("HelloClientIntHandler.channelRead");
        ByteBufresult = (ByteBuf) msg;
        byte[] result1 = new byte[result.readableBytes()];
        result.readBytes(result1);
        System.out.println("Server
said:" + new String(result1));
        result.release();
    }
 
    // 连接成功后,向server发送消息
    @Override
    public void channelActive(ChannelHandlerContextctx) throws Exception {
        logger.info("HelloClientIntHandler.channelActive");
        String msg =
"Are you ok?";
        ByteBuf encoded = ctx.alloc().buffer(4 * msg.length());
        encoded.writeBytes(msg.getBytes());
        ctx.write(encoded);
        ctx.flush();
    }
}
六、还有log4j.xml文件:
<?xml version="1.0"?>
<!DOCTYPElog4j:configuration SYSTEM
"log4j.dtd">
 
<log4j:configurationxmlns:log4j="http://jakarta.apache.org/log4j/">
    <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%-5p]
[%d] [%t][%c] %m%n"/>
        </layout>
    </appender>
   
    <appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="File" value="./log/netty.log"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%-5p]
[%d] [%t][%c] %m%n"/>
        </layout>
    </appender>
   
    <appender name="FILE_ERR" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="File" value="./log/netty_err.log"/>
        <param name="Threshold" value="ERROR"
/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%-5p]
[%d] [%t][%c] %m%n"/>
        </layout>
    </appender>    

   
    <logger name="io.netty" additivity="false">
        <level value="INFO,DEBUG" />
        <appender-refref="FILE"
/>
        <appender-refref="FILE_ERR"
/>
        <appender-refref="CONSOLE"
/>
    </logger>
    <logger name="com.yao" additivity="false">
        <level value="INFO,DEBUG" />
        <appender-refref="FILE"
/>
        <appender-refref="FILE_ERR"
/>
        <appender-refref="CONSOLE"
/>
    </logger>
   
    <root>
       
      <level value="debug"/>
        <appender-refref="FILE"/>
        <appender-refref="CONSOLE"/>
        <appender-refref="FILE_ERR"
/>
    </root>
 
</log4j:configuration>
总结: 
通过上面简单的实例可以发现: 

1、在没有任何encoder、decoder的情况下,Netty发送接收数据都是按照ByteBuf的形式,其它形式都是不合法的。 

2、接收发送数据操作都是通过handler实现的,handler在netty中占据了非常重要的位置。 

3、netty的handler是基于事件触发的,例如当client连接server成功后,client中的HelloClientIntHandler的channelActive方法会自动调用。 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: