今天下班之后无聊,学习了一下长链接的一款非常秀的框架——netty,netty在很多?️java开发的中间件中都有很坚实的地位。于是,在下班之余我学习了一下这款优秀的框架。
从开始搭建到运行
需要准备
jdk8 、 idea maven
新建一个项目,然后分别创建server端和client端(也就是提供者和调用者) 在pom.xml内加入netty的jar包
代码语言:javascript复制<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>5.0.0.Alpha2</version>
</dependency>
Netty创建全部都是实现自AbstractBootstrap。客户端的是Bootstrap,服务端的则是ServerBootstrap
创建服务端
根据api提供的接口,服务端需要继承ServerBootstrap类,看一下该类的继承关系图
它是实现了抽象类,该抽象类即netty的核心之一
代码语言:javascript复制package org.choviwu.movie.netty.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class ServerMain {
public static void main(String[] args) {
//EventLoopGroup 是在4.x版本中提出来的一个新概念。用于channel的管理。服务端需要两个。 一个是boss线程一个是worker线程。
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(eventLoopGroup, workerGroup)
.channel(NioServerSocketChannel.class)
//这里是自定义的handler,用来初始化通道
.childHandler(new HelloServerInitializer());
// 服务器绑定端口监听 端口10000 同步接收
ChannelFuture future = serverBootstrap.bind(10000).sync();
Channel channel = future.channel();
// 监听服务器关闭监听
future.channel().closeFuture().sync();
}catch (InterruptedException ex){
}finally {
//shutdown
eventLoopGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
其实,我们目的就是当客户端输入消息时,服务端能够收到该消息。 DelimiterBasedFrameDecoder Netty在官方网站上提供的示例显示 有这么一个解码器可以简单的消息分割。 其次 在decoder里面我们找到了String解码编码器。着都是官网提供给我们的。
代码语言:javascript复制package org.choviwu.movie.netty.server;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class HelloServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline channelPipeline = ch.pipeline();
channelPipeline.addLast("framer",new DelimiterBasedFrameDecoder(8500, Delimiters.lineDelimiter()));
channelPipeline.addLast("decoder",new StringDecoder());
channelPipeline.addLast("encoder",new StringEncoder());
channelPipeline.addLast("handler",new HelloHandler());
System.out.println("Socket Channel " ch);
}
}
上面的三个解码和编码都是系统。 另外我们自己的Handler怎么办呢。在最后我们添加一个自己的Handler用于写自己的处理逻辑。
代码语言:javascript复制package org.choviwu.movie.netty.server;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.net.InetAddress;
public class HelloHandler extends SimpleChannelInboundHandler<String> {
//当客户端发送消息时,服务端可以从该方法上获取到该消息值
@Override
protected void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("Recieve value is : " msg);
ctx.writeAndFlush("成功接收Msg的值。。。" msg);
}
/**
* 覆盖 channelActive 方法 在channel被启用的时候触发 (在建立连接的时候)
* channelActive 和 channelInActive 在后面的内容中讲述,这里先不做详细的描述
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("RemoteAddress : " ctx.channel().remoteAddress() " active !");
System.out.println("local Address " ctx.channel().localAddress());
// 等同于下一句 ctx.write(""); ctx.flush();
ctx.writeAndFlush( "Welcome to " InetAddress.getLocalHost().getHostName() " service!n");
//
super.channelActive(ctx);
}
}
创建客户端
客户端代码相对较少,拿到消息到返回值与服务端的代码可公用
代码语言:javascript复制package org.choviwu.movie.netty.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 org.choviwu.movie.netty.server.HelloServerInitializer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class ClientMain {
public static void main(String[] args) {
//新建一个线程 用来发送消息
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
//客户端的父类
Bootstrap bootstrap = new Bootstrap();
//用NioSocketChannel来进行管理通道
//自定义handler 用来对消息的编码等进行处理 与服务端一致
bootstrap.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.handler(new HelloServerInitializer())
;
try {
//连接到服务端的ip和地址 并打开通道
//在控制台上输入字符串 服务端即可监听到
Channel channel = bootstrap.connect("127.0.0.1", 10000).sync().channel();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
String line = reader.readLine();
if(line==null){
continue;
}
/**
* 向服务端发送在控制台输入的文本 并用"rn"结尾
* 之所以用rn结尾 是因为我们在handler中添加了 DelimiterBasedFrameDecoder 帧解码。
* 这个解码器是一个根据n符号位分隔符的解码器。所以每条消息的最后必须加上n否则无法识别和解码
*/
channel.writeAndFlush(line "rn");
}
} catch (InterruptedException | IOException ex) {
ex.printStackTrace();
} finally {
eventLoopGroup.shutdownGracefully();
}
}
}