开发环境搭建
需要说明的是笔者使用的编辑器是idea,同时还要安装gradle插件,因为学习netty的过程是和gradle一起的,所以后面的netty学习都会使用gradle
gradle环境搭建
-
官网下载 gradle
-
在
.bash_profile
文件中配置Gradle环境变量
GRADLE_HOME=/Users/sirtian/Documents/environment/gradle-5.0
PATH=:$GRADLE_HOME/bin:$PATH:.
export GRADLE_HOME
-
在控制台使用
source .bash_profile
命令对修改后的配置文件进行更新 -
在控制 台使用
gradle -version
命令查看是否配置成功,如果成功输出gradle的版本则说明配置成功
使用idea创建gradle项目

此处创建完毕后,需要在gradle的配置文件中添加netty的依赖文件,因为后期会对源码进行分析,所以此处下载包含源码的jar包,可以在此处找到gradle的依赖并将其加到gradle配置中,如下

服务端代码
TimeServer.java
package com.sirTian;
import com.sun.security.ntlm.Server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import java.net.SocketOption;
public class TimeServer {
private class ChildChannelHandler extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new TimeServerHandler());
}
}
public void bind(int port) throws Exception{
// EventLoopGroup是线程组,这里包含两个线程组,分别用于监听客户端连接和
// 处理客户端读写事件
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workgroup = new NioEventLoopGroup();
try{
// ServerBootstrap 是服务端启动辅助类
ServerBootstrap bootstrap = new ServerBootstrap();
// group方法将两个线程组作为参数绑定到启动类中,channel方法绑定channel,对于server这里绑定
// NioServerSocketChannel,childHandler方法绑定到具体的处理方法
bootstrap.group(bossGroup,workgroup).channel(NioServerSocketChannel.class)
.childHandler(new ChildChannelHandler());
// 先调用bind方法绑定监听端口,然后调用sync方法,这是一个同步方法,用于等待绑定操作完成
// future对象类似于Jdk的Future
ChannelFuture future = bootstrap.bind(8080).sync();
future.channel().closeFuture().sync();
}finally {
// 关闭线程组关联的资源
bossGroup.shutdownGracefully();
workgroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception{
new TimeServer().bind(8080);
}
}
TimeServerHandler.java
package com.sirTian;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class TimeServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf byteBuf = (ByteBuf)msg;
byte[] req = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(req);
String body = new String(req,"UTF-8");
System.out.println("QUERY TIME ORDER:"+body);
String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body)?new java.util.Date(System.
currentTimeMillis()).toString():"Bad order";
ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
ctx.write(resp);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
客户端代码
TimeClient.java
package com.sirTian;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
public class TimeClient {
private class ChildChannelHandler extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new TimeServerHandler());
}
}
public void connect(int port) throws Exception{
// 这里不同于服务器端,因为只需要连接即可,故只用创建一个线程组
EventLoopGroup group = new NioEventLoopGroup();
try{
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group).channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new TimeClientHandler());
}
});
// 这里区别于服务端的bind方法
ChannelFuture future = bootstrap.connect("localhost",8080).sync();
future.channel().closeFuture().sync();
}finally {
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception{
new TimeClient().connect(8080);
}
}
TimeClientHandler.java
package com.sirTian;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class TimeClientHandler extends ChannelInboundHandlerAdapter {
private ByteBuf firstMessage;
public TimeClientHandler() {
byte[] request = "QUERY TIME ORDER".getBytes();
firstMessage = Unpooled.buffer(request.length);
firstMessage.writeBytes(request);
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
ctx.writeAndFlush(firstMessage);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
ByteBuf byteBuf = (ByteBuf) msg;
byte[] req = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(req);
String body = new String(req, "UTF-8");
System.out.println("Now is:" + body);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// 释放资源
ctx.close();
}
}
运行结果


总结
通过以上代码可以大概了解到使用netty创建应用的过程,以及其相对于jdk原生api创建应用程序的便捷性,后面会慢慢接触netty中更加高级的东西。
网友评论