前言
上一篇文章简要地介绍了Netty框架能够做什么以及其中所涉及的一些技术细节。而本文主要是从一个最简单的Netty程序入手,这样我们才能更快地熟悉Netty这个框架。
我也在网上找过很多教程,但是很多教程基本都是基于Netty3的,Netty4的教程比较少,但是Netty3到Netty4,里面API的变化可以说是翻天覆地,而现在普遍都是用Netty4,所以大多数教程都不太适合新手学习了,包括我,在工作中也是用Netty4的,这也是没办法的事,没理由我让公司的项目转变成用Netty3吧。当然英文水平好的可以直接看Netty官网指南,或者看《Netty In Action 第五版》,可惜这么好的书没出中文版,但是这也是不能奢望太多的,就算有中文版,若翻译粗糙,那也是误人子弟的。
由于自己的英文水平也是马马虎虎,所以我也是硬着头皮看了一点点,现在我才感受到当初自己没有学好英文真是不应该啊,不过以后自己真心要恶补英语了。
从HelloWorld开始
不管学什么编程语言,框架技术,从编写HelloWorld开始无疑是最简单快捷地认识新事物的。下面是一个最简单的Netty程序,话不多说,直接上代码
HelloServer服务器代码
public class HelloServer {
private int port;
public HelloServer(int port) {
this.port = port;
}
public void start() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new HelloServerHandler());
}
}).option(ChannelOption.SO_KEEPALIVE, true);
// 绑定端口, 并开始接受正到来的客户端连接
ChannelFuture f = b.bind(port).sync();
// 一直等待, 直到服务端socket已经关闭为止
f.channel().closeFuture().sync();
} finally {
// 释放所有的资源
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new HelloServer(5000).start();
}
}
HelloServerHandler服务器处理程序或服务器处理器
// 这里一般写服务器端的业务逻辑代码
public class HelloServerHandler extends ChannelInboundHandlerAdapter {
// channelActive 在与客户端连接建立并准备进行通信的时候被调用
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Hi, I'm HelloServer!");
}
// channelRead 在每当收到服务端发送的新数据时被调用
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
}
// exceptionCaught 在出现Throwable对象时, 即Netty由于IO出错或处理器处理事件抛出异常时被调用
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
HelloClient客户端代码
public class HelloClient {
private String host;
private int port;
public HelloClient(String host, int port) {
this.host = host;
this.port = port;
}
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new HelloClientHandler());
}
});
// 绑定ip地址和端口, 并使其尝试连接服务端
ChannelFuture f = b.connect(host, port).sync();
// 一直等待, 直到该连接已经断开为止
f.channel().closeFuture().sync();
} finally {
// 释放资源
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new HelloClient("127.0.0.1", 5000).start();
}
}
HelloClientHandler服务器处理程序或服务器处理器
public class HelloClientHandler extends ChannelInboundHandlerAdapter {
// channelActive 在与服务端连接建立并准备进行通信的时候被调用
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Hello, I'm HelloClient~");
}
// channelRead 在每当收到客户端发送的新数据时被调用
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
}
// exceptionCaught 在出现Throwable对象时, 即Netty由于IO出错或处理器处理事件抛出异常时被调用
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
}
}
代码中的一些概念
这个服务端/客户端代码并没有进行互相通信,里面的所做的只是简单的打印,毕竟只是HelloWorld程序,但也有足够的东西让我们学习了。
1.EventLoopGroup
它是一个用于处理I/O操作的多线程事件循环线程池,服务端一般要用2个EventLoopGroup,boss线程池用于处理接收的连接,接收到连接后,它就会把连接信息注册到worker线程池上;而worker线程池用于处理该连接的各种事件和I/O操作。而Netty为各种传输方式提供了多种EventLoopGroup的实现,NioEventLoopGroup就是其中一种。
2.ServerBootstrap
这是一个简化建立Netty服务端操作的帮助类。
3.ChannelInitializer
它是一个特殊的处理类,专门用于配置新Channel;使用它来配置Channel就像是通过ChannelPipeline配置新Channel有一样的效果。
以上这些都是最基本的,代码中比较重要的方法它的作用就如注释所写。接下来,只需要先启动服务端,再启动客户端,你就能看到服务端和客户端都会打印相应的消息了。