MangoCool

Netty框架简单示例

2015-10-30 10:55:46   作者:MangoCool   来源:MangoCool

之前使用Mina框架,了解到Netty,号称高效,简洁,快速,更优于Mina。就让我忍不住开始倒腾一番。Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。Netty 是一个基于NIO的客户,服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用。

还是老一套,先到官网弄个example跑跑,跑通了,看看代码,再去深入原理。以下就是我从官网弄过来的例子,稍有更改。

依赖:jdk1.7,netty5.0.0.Alpha2

开发环境:ideaIU-14.1.4

测试环境:win7

建立maven工程NettyDemo,在pom.xml配置文件添加必要的依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>NettyDemo</groupId>
    <artifactId>NettyDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>

        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>5.0.0.Alpha2</version>
        </dependency>

    </dependencies>

</project>

SimpleChatClientHandle.java类:

package com.mangocool.netty;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

/**
 * Created by MANGOCOOL on 2015/10/30.
 */
public class SimpleChatClientHandler extends  SimpleChannelInboundHandler<String> {

//    优先级高于messageReceived方法,有了这个方法就会屏蔽messageReceived方法
//    @Override
//    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//        System.out.println(msg.toString());
//    }

    @Override
    protected void messageReceived(ChannelHandlerContext ctx, String msg)
            throws Exception {
        System.out.println(msg);
    }
}
SimpleChatClientInitializer.java类:
package com.mangocool.netty;

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;

/**
 * Created by MANGOCOOL on 2015/10/30.
 */
public class SimpleChatClientInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    public void initChannel(SocketChannel ch) throws Exception
    {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
        pipeline.addLast("decoder", new StringDecoder());
        pipeline.addLast("encoder", new StringEncoder());
        pipeline.addLast("handler", new SimpleChatClientHandler());
    }
}
SimpleChatClient.java类:
package com.mangocool.netty;

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.util.Scanner;

/**
 * Created by MANGOCOOL on 2015/10/30.
 */
public class SimpleChatClient {

    private static String host = "localhost";
    private static int port = 8080;

    public static void main(String[] args) throws Exception
    {
        new SimpleChatClient(host, port).run();
    }

    public SimpleChatClient(String host, int port)
    {
        this.host = host;
        this.port = port;
    }

    public void run() throws Exception
    {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap  = new Bootstrap()
                    .group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new SimpleChatClientInitializer());
            Channel channel = bootstrap.connect(host, port).sync().channel();
            Scanner sc = new Scanner(System.in);
            System.out.println("please enter...");
            boolean exit = false;
            // 输入exit,退出系统
            while(!exit)
            {
                String str = sc.next();
                channel.writeAndFlush(str + "\r\n");
                if(str.equalsIgnoreCase("exit"))
                {
                    exit = true;
                    channel.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }
}
SimpleChatServerHandler.java类:
package com.mangocool.netty;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;

/**
 * Created by MANGOCOOL on 2015/10/30.
 */
public class SimpleChatServerHandler extends SimpleChannelInboundHandler<String> {

    public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel incoming = ctx.channel();
        for (Channel channel : channels) {
            channel.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 加入\n");
        }
        channels.add(ctx.channel());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel incoming = ctx.channel();
        for (Channel channel : channels) {
            channel.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 离开\n");
        }
        channels.remove(ctx.channel());
    }

//    优先级高于messageReceived方法,有了这个方法就会屏蔽messageReceived方法
//    @Override
//    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//        System.out.println("channelRead");
//        Channel incoming = ctx.channel();
//        for (Channel channel : channels) {
//            if (channel != incoming){
//                channel.writeAndFlush("[" + incoming.remoteAddress() + "]" + msg + "\n");
//            } else {
//                channel.writeAndFlush("server: " + msg + "\n");
//            }
//        }
//    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Channel incoming = ctx.channel();
        System.out.println("client "+incoming.remoteAddress()+" 在线");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel incoming = ctx.channel();
        System.out.println("client "+incoming.remoteAddress()+" 掉线");
    }

    @Override
    protected void messageReceived(ChannelHandlerContext ctx, String msg)
            throws Exception {
        Channel incoming = ctx.channel();
        for (Channel channel : channels) {
            if (channel != incoming){
//                System.out.println("[" + incoming.remoteAddress() + "] " + msg);
                channel.writeAndFlush("[" + incoming.remoteAddress() + "] " + msg + "\n");
            } else {
//                System.out.println("server: " + msg);
                channel.writeAndFlush("server: " + msg + "\n");
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        Channel incoming = ctx.channel();
        System.out.println("client "+incoming.remoteAddress()+" 异常");
        // 当出现异常就关闭连接
        cause.printStackTrace();
        ctx.close();
    }

}
SimpleChatServerInitializer.java类:
package com.mangocool.netty;

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;

/**
 * Created by MANGOCOOL on 2015/10/30.
 */
public class SimpleChatServerInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    public void initChannel(SocketChannel ch) throws Exception
    {
        ChannelPipeline pipeline = ch.pipeline();

        pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
        pipeline.addLast("decoder", new StringDecoder());
        pipeline.addLast("encoder", new StringEncoder());
        pipeline.addLast("handler", new SimpleChatServerHandler());

        System.out.println("client "+ch.remoteAddress() +" 连接上");
    }
}
SimpleChatServer.java类:
package com.mangocool.netty;

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;

/**
 * Created by MANGOCOOL on 2015/10/30.
 */
public class SimpleChatServer {

    private static int port = 8080;

    public SimpleChatServer(int port) {
        this.port = port;
    }

    public void run() throws Exception {

        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new SimpleChatServerInitializer())
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            System.out.println("server 启动了");

            // 绑定端口,开始接收进来的连接
            ChannelFuture f = b.bind(port).sync();

            // 等待服务器  socket 关闭 。
            // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。
            f.channel().closeFuture().sync();

        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();

            System.out.println("server 关闭了");
        }
    }

    public static void main(String[] args) throws Exception
    {
        new SimpleChatServer(port).run();
    }
}

到此就可以开始测试了,测试时建议开启3个client,效果更明显,以下是我的测试结果:

server端:

client01端:

client02端:

client03端:

到此例子就结束了,小伙伴们,动手试试!

还有一个叫做Grizzly的NIO开源框架,有时间也可以学习学习!

官网:https://grizzly.java.net/overview.html


参考来源:

官网:http://netty.io/wiki/user-guide-for-5.x.html

译文:http://ifeve.com/netty5-user-guide/

示例:https://github.com/netty/netty/tree/master/example/src/main/java/io/netty/example

推荐书籍:中文名:《Netty权威指南》 外文名:Netty:The Definitive Guide 作者:李林锋 

他的文章:http://www.infoq.com/cn/author/%E6%9D%8E%E6%9E%97%E9%94%8B#文章

标签: Netty Java NIO Socket Demo

分享:

上一篇doesn't deregister JDBC driver, causing memory leak

下一篇Mina框架的简述

关于我

崇尚极简,热爱技术,喜欢唱歌,热衷旅行,爱好电子产品的一介码农。

座右铭

当你的才华还撑不起你的野心的时候,你就应该静下心来学习,永不止步!

人生之旅历途甚长,所争决不在一年半月,万不可因此着急失望,招精神之萎葸。

Copyright 2015- 芒果酷(mangocool.com) All rights reserved. 湘ICP备14019394号

免责声明:本网站部分文章转载其他媒体,意在为公众提供免费服务。如有信息侵犯了您的权益,可与本网站联系,本网站将尽快予以撤除。