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方法会自动调用。