版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lms1719/article/details/70314645
Netty 4.x 实战详解
目前Netty的最新稳定版本是 Netty 4.1.9, 本文根据该版本进行开发介绍。
开发前准备工作:
到Netty官网(http://netty.io/downloads.html),下载开始所需的Netty包:netty-all-4.1.9.Final.jar;
安装Java开发环境,这里使用的是Jdk8;
这里使用的编辑器是Intellij IDEA,也可以根据自己的喜好,选择其他的,比如Eclipse等。
接下来,我们用Netty实现一个demo。主要功能如下:
1、服务端启动,等待接受客户端的连接和处理请求;
2、客户端启动和服务端建立连接,服务器返回“连接成功!”;
3、客户端和服务器进行数据传输操作。
代码实现
一、 服务器
1、服务器启动逻辑(DemoServer.java)
package server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* 服务器启动逻辑
*/
public class DemoServer {
public static void main(String[] args) throws Exception {
int port = 8000;
if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
//采用默认值
}
}
new DemoServer().bind(port);
}
public void bind(int port) throws Exception {
//配置服务端的NIO线程组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ServerChannelInitializer());
//绑定端口,同步等待成功
ChannelFuture f = b.bind(port).sync();
//等待服务器监听端口关闭
f.channel().closeFuture().sync();
} finally {
//优雅退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
2、服务器Channel通道初始化设置(ServerChannelInitializer .java)
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* 服务器Channel通道初始化设置
*/
public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
//字符串解码和编码
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
//服务器的逻辑
pipeline.addLast("handler", new DemoServerHandler());
}
}
3、服务器业务逻辑(DemoServerHandler.java)
package server;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.net.Inet4Address;
/**
* 服务器业务逻辑
*/
public class DemoServerHandler extends SimpleChannelInboundHandler {
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("Client say : " + msg.toString());
//返回客户端消息 - 我已经接收到了你的消息
ctx.writeAndFlush("Received your message : " + msg.toString());
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("RemoteAddress : " + ctx.channel().remoteAddress() + " active !");
ctx.writeAndFlush("连接成功!");
super.channelActive(ctx);
}
}
二、 客户端
1、客户端启动逻辑(DemoClient.java)
package client;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.io.BufferedReader;
import java.io.InputStreamReader;
/**
* 客户端启动逻辑
*/
public class DemoClient {
public static String host = "127.0.0.1"; //服务器IP地址
public static int port = 8000; //服务器端口
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ClientChannelInitializer());
//连接客户端
Channel channel = b.connect(host, port).sync().channel();
//控制台输入
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (;;) {
String line = in.readLine();
if (line == null) {
continue;
}
//向服务端发送数据
channel.writeAndFlush(line);
}
} finally {
//优雅退出,释放线程池资源
group.shutdownGracefully();
}
}
}
2、客户端Channel通道初始化设置(ClientChannelInitializer .java)
package client;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* 客户端Channel通道初始化设置
*/
public class ClientChannelInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
//字符串解码和编码
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
//客户端的逻辑
pipeline.addLast("handler", new DemoClientHandler());
}
}
3、客户端业务逻辑(DemoClientHandler.java)
package client;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* 客户端业务逻辑
*/
public class DemoClientHandler extends SimpleChannelInboundHandler {
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("Server say : " + msg.toString());
}
}
运行结果
- 先启动服务器,再启动客户端。
- 在客户端的控制台输入“服务端,你好!”,然后按“Enter”键,将数据发送到服务端。