本文通过一个简单的例子,来讲解netty最基本的用法。
首先,创建工程mynetty,引入netty的依赖包:
创建好之后,开始编码:
1. 新建类NettyServer
2. 运行程序,打开命令行,输入:telnet 127.0.0.1 8080,在控制台会出现:
表示有客户端连接到了server,并且打印出了客户端的信息。
3. 任意输入一个字符(如:a),在控制台会出现:
这就意味着Server收到了来自client的message,打印出了客户端信息以及message的基本信息。而在命令行窗口会出现我们刚才输入的字符a。
4. 当关闭命令行窗口时,控制台会出现:
表示连接已经关闭了。
从现象到本质,下面来做简单的解释。服务器的主要逻辑都放在类Server中的,所以来看一下该类中是如何启动服务器、接收消息的。
首先是构造方法:
1. 初始化ServerBootstrap,并注入NioServerSocketChannelFactory,用于创建通道(channel)等。从这里可以看出是通过Nio的方式来处理的,factory中放入两个线程池,主要用于接收connect和message。
2. 为通道以及子通道(带前缀”child.”)设置相关的属性(socket属性),此处暂不详细介绍。
3. 向ChannelPipline中添加处理器(ChannelHandler),用于处理连接和消息。
MyHandler继承了SimpleChannelHandler,并且重写了方法:channelClosed、channelConnected、messageReseived,方法的参数为ChannelHandlerContext和ChannelEvent。ChannelHandlerContext为通道上下文,event中便带有消息和连接的信息。
channelConnected方法在接到来自客户端的连接时触发(这里只是打印了收到的连接的信息),所以在执行telnet命令时,看到控制台会有相应的输出。
MessageReseived方法在接收到消息是会触发,这里会交给processMessage方法处理,这里只是简单的把接收到的信息写回客户端。所以在命令行窗口中会看到我们写入的字母信息。
ChannelClosed方法在关闭连接的时候被调用,当我们关闭命令行窗口的时候,就会看到控制台打印出相应的信息。
当然,ChannelHander的接口不止这么三个,除了SimpleChannelHandler以外还有很特殊的实现,这里只做简单介绍。
初始化完成之后,我们调用server.config(int port)方法注入需要绑定的端口信息,这里为8080。
最后调用server.start()方法,服务器便启动起来了。
首先,创建工程mynetty,引入netty的依赖包:
- <dependency>
- <groupId>io.netty</groupId>
- <artifactId>netty</artifactId>
- <version>3.5.6.Final</version>
- </dependency>
创建好之后,开始编码:
1. 新建类NettyServer
- package com.netty.intr;
- import java.net.InetSocketAddress;
- import java.util.concurrent.Executors;
- import org.jboss.netty.bootstrap.ServerBootstrap;
- import org.jboss.netty.channel.Channel;
- import org.jboss.netty.channel.ChannelHandlerContext;
- import org.jboss.netty.channel.ChannelStateEvent;
- import org.jboss.netty.channel.MessageEvent;
- import org.jboss.netty.channel.SimpleChannelHandler;
- import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
- public class NettyServer {
- final static int port = 8080;
- public static void main(String[] args) {
- Server server = new Server();
- server.config(port);
- server.start();
- }
- }
- class Server {
- ServerBootstrap bootstrap;
- Channel parentChannel;
- InetSocketAddress localAddress;
- MyChannelHandler channelHandler = new MyChannelHandler();
- Server() {
- bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(
- Executors.newCachedThreadPool(), Executors
- .newCachedThreadPool()));
- bootstrap.setOption("reuseAddress", true);
- bootstrap.setOption("child.tcpNoDelay", true);
- bootstrap.setOption("child.soLinger", 2);
- bootstrap.getPipeline().addLast("servercnfactory", channelHandler);
- }
- void config(int port) {
- this.localAddress = new InetSocketAddress(port);
- }
- void start() {
- parentChannel = bootstrap.bind(localAddress);
- }
- class MyChannelHandler extends SimpleChannelHandler {
- @Override
- public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
- throws Exception {
- System.out.println("Channel closed " + e);
- }
- @Override
- public void channelConnected(ChannelHandlerContext ctx,
- ChannelStateEvent e) throws Exception {
- System.out.println("Channel connected " + e);
- }
- @Override
- public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
- throws Exception {
- try {
- System.out.println("New message " + e.toString() + " from "
- + ctx.getChannel());
- processMessage(e);
- } catch (Exception ex) {
- ex.printStackTrace();
- throw ex;
- }
- }
- private void processMessage(MessageEvent e) {
- Channel ch = e.getChannel();
- ch.write(e.getMessage());
- }
- }
- }
2. 运行程序,打开命令行,输入:telnet 127.0.0.1 8080,在控制台会出现:
- Channel connected [id: 0x29b7df26, /127.0.0.1:51554 => /127.0.0.1:8080] CONNECTED: /127.0.0.1:51554
表示有客户端连接到了server,并且打印出了客户端的信息。
3. 任意输入一个字符(如:a),在控制台会出现:
- New message [id: 0x29b7df26, /127.0.0.1:51554 => /127.0.0.1:8080] RECEIVED: BigEndianHeapChannelBuffer(ridx=0, widx=1, cap=1) from [id: 0x29b7df26, /127.0.0.1:51554 => /127.0.0.1:8080]
这就意味着Server收到了来自client的message,打印出了客户端信息以及message的基本信息。而在命令行窗口会出现我们刚才输入的字符a。
4. 当关闭命令行窗口时,控制台会出现:
- Channel closed [id: 0x29b7df26, /127.0.0.1:51554 :> /127.0.0.1:8080] CLOSED
表示连接已经关闭了。
从现象到本质,下面来做简单的解释。服务器的主要逻辑都放在类Server中的,所以来看一下该类中是如何启动服务器、接收消息的。
首先是构造方法:
1. 初始化ServerBootstrap,并注入NioServerSocketChannelFactory,用于创建通道(channel)等。从这里可以看出是通过Nio的方式来处理的,factory中放入两个线程池,主要用于接收connect和message。
- bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(
- Executors.newCachedThreadPool(), Executors
- .newCachedThreadPool()));
2. 为通道以及子通道(带前缀”child.”)设置相关的属性(socket属性),此处暂不详细介绍。
- bootstrap.setOption("reuseAddress", true);
- bootstrap.setOption("child.tcpNoDelay", true);
- bootstrap.setOption("child.soLinger", 2);
3. 向ChannelPipline中添加处理器(ChannelHandler),用于处理连接和消息。
- bootstrap.getPipeline().addLast("servercnfactory", channelHandler);
MyHandler继承了SimpleChannelHandler,并且重写了方法:channelClosed、channelConnected、messageReseived,方法的参数为ChannelHandlerContext和ChannelEvent。ChannelHandlerContext为通道上下文,event中便带有消息和连接的信息。
channelConnected方法在接到来自客户端的连接时触发(这里只是打印了收到的连接的信息),所以在执行telnet命令时,看到控制台会有相应的输出。
MessageReseived方法在接收到消息是会触发,这里会交给processMessage方法处理,这里只是简单的把接收到的信息写回客户端。所以在命令行窗口中会看到我们写入的字母信息。
ChannelClosed方法在关闭连接的时候被调用,当我们关闭命令行窗口的时候,就会看到控制台打印出相应的信息。
当然,ChannelHander的接口不止这么三个,除了SimpleChannelHandler以外还有很特殊的实现,这里只做简单介绍。
初始化完成之后,我们调用server.config(int port)方法注入需要绑定的端口信息,这里为8080。
最后调用server.start()方法,服务器便启动起来了。