netty学习笔记(一) -- 创建一个简单的客户端服务器通信实例

完全是零基础开始的后端开发,所以该系列笔记(或者称为教程也可以)是完全假设没有任何预备知识的,但是前提是:1. Java基础;2. maven配置知识(gradle);

环境配置

本项目基于maven进行学习启动,我们需要用到的工具和依赖:

  • maven安装与配置(详见上一篇)
  • eclipe(IDE for Java web)
  • JDK 1.7 +
  • netty latest (netty download)
  • telnet(linux/unix 默认可用,windows需配置)

配置十分容易,就是将相关的jar包放置到lib目录中,同时在pom.xml中添加依赖即可。


项目结构

在pom.xml中添加依赖如下:

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

项目说明

此次教程旨在通过netty搭建一个本地服务器,采用telnet连接的方式实现向服务端口发送消息,验证客户端和服务器的连通性,在服务端实时打印出客户端发送过来的信息,借此对netty的用法有一个初步的理解。
同时为了进阶netty,还有以下资料参考:
先扔几个参考学习的网页:

netty 官方API: netty link

netty 中文指南:netty 中文

netty 优秀博客netty 入门

关于NIO基础的知识:

https://my.oschina.net/andylucc/blog/614295
http://www.cnblogs.com/dolphin0520/p/3919162.html 
http://blog.csdn.net/wuxianglong/article/details/6604817

服务代码构建

服务器的作用是根据客户端发送过来的信息进行解析后执行对应的事务处理策略,姑且我们将这个称之为“事务策略”。
不同的事务策略是为了满足客户端各种请求(比如:数据库增删改查、文件上传下载等),而通过定义协议,通过特定的请求字段及参数等,发送到服务器进行特定事务的执行并返回结果。

在本例中,则通过一个简单的事务策略实例-打印客户端消息

创建打印客户端消息的事务策略

package geekfish.NettyServer;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;

public class SimpleServerTestHandler extends ChannelHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // get the msg from clients
        try {
            ByteBuf in = (ByteBuf) msg;
            System.out.println("the msg from client is :" + in.toString(CharsetUtil.UTF_8) + " from "
                    + ctx.hashCode());
        } finally {
            // 我们必须要对引用计数的对象进行手动释放
            ReferenceCountUtil.release(msg);
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        // TODO Auto-generated method stub
        super.channelReadComplete(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // TODO Auto-generated method stub
        super.exceptionCaught(ctx, cause);
    }
}

如我们之前所说,当客户端发送特定的请求时,我们在服务器端接收到客户端报文后并进行解析从而确定选用哪一个事务策略,在此我们引入两个问题:

  • 如何制定请求类型和在服务器端解析

在此,我们简化了流程,只要客户端与服务器建立了连接,那么服务器就会将客户端发送过来的信息无脑地打印出来,并不涉及多业务类型的解析;

  • 谁来负责接收并处理客户端信息

因此,仅有一个事务策略肯定是不够的,需要有主体去执行才行,可以想象这个主体主要负责的工作:接收所有客户端信息、解析客户端信息、执行客户端请求的任务、返回执行结果给客户端。所以我们还有一个主体需要实现,这里我们姑且将之称为“服务端主体”。

创建服务端主体

package geekfish.NettyServer;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class MainServer {
    private int port;

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

    public void run() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        System.out.println("ready to run port =>" + port);
        try {
            // 我们需要创建一个ServerBootstrap启动NIO服务
            ServerBootstrap bootstrap = new ServerBootstrap();
            // 我们需要设置boss Group 和 worker Group
            bootstrap = bootstrap.group(bossGroup, workerGroup);
            // 设置channel
            bootstrap = bootstrap.channel(NioServerSocketChannel.class);
            // 我们通过增加pipeline的方式给channel增加事务处理监听
            bootstrap = bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {

                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    // 我们可以在此处增加各种事务处理的监听,比如xxxServerHandler
                    ch.pipeline().addLast(new SimpleServerTestHandler());
                    // you can still add other handlers here
                }
            });

            // 我们可以在此处进行参数的设置
            bootstrap = bootstrap.option(ChannelOption.SO_BACKLOG, 128);
            // 设置子连接的参数
            bootstrap = bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
            // 绑定端口并启动接收客户端信息
            ChannelFuture channelFuture = bootstrap.bind(port).sync();
            // 一直等待循环接收信息直到socket关闭
            channelFuture.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
    
    //the main entrance to run this instance
    public final static void main(String[] args) throws Exception{
        int port = 8080;
        if(args.length > 0)
            port = Integer.parseInt(args[0]);
        new MainServer(port).run();
        System.out.println("the server start listening...");
    }
}

代码验证测试

到此为止,简化版的项目已经基本完成,现在既可以通过talnet连接进行简单会话测试。

  • 启动运行 服务端主体;

run MainServer,当然此处你可以带上端口号参数,如果懒到啥都不干,那就是8080了,记住这个端口号,因为客户端需要与这个端口创建连接;

  • 在terminal中创建连接;
telnet localhost 8080

当然这里的8080需要替换为你当前启动的端口号,当连接创建之后,则可以在terminal会话窗口内向服务端发送消息啦,此时打开eclipse的控制台就可以看到每一条从客户端发过来的信息。

如果使用的是windows,注意windows下默认未开启telnet连接,所以直接在cmd中输入以上指令可能无法生效,需要去到'控制面板>>程序>>打开或者关闭windows功能'里面勾选上'telnet客户端'。

写在最后的话

楼主是计算机视觉这块的,所以比较偏重于应用层,对于前后端的开发基本算是零起步,但是通过接触前后端开发,最深的感触就是各种各样并且飞速迭代的框架,开发者入门时可能会遇到各种选择问题,但是从楼主的经历来看,框架是封装好的工具,切不可不求甚解地强记框架API,而是要大致理解后端框架共性的业务流程及模块划分。

由于走过弯路,没有使用任何框架上来就是继承Servlet去实现,虽然最后堆了一坨代码(包括自定义json封装解析类、数据库操作类、文件操作类等),所以即使实现了简单的后台功能,但是对于高并发、数据库高性能开发等均一无所知。然而与此同时,因为DIY过一个这样简易的结构,麻雀虽小,但是也具备基本必要模块,所以在此基础上,再去看各大流行框架,就会禁不住思考各个模块对应的实现细节,这一点对上手新框架以及对现有框架的理解都是挺有帮助的。

最后,希望这个教程能够坚持更新和创造一定的价值。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,638评论 18 139
  • 前奏 https://tech.meituan.com/2016/11/04/nio.html 综述 netty通...
    jiangmo阅读 5,846评论 0 13
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,218评论 11 349
  • 朋友们大家好,准备好了个人网站准备发布的时候是不是都是一筹莫展,万脸懵逼?服务器都是小200一年,还要准备FTP?...
    cherish薯条阅读 6,542评论 21 26
  • 姐姐的姐姐带我逛旺山。 生活永远不止表面的光鲜,我一直羡慕的姐妹二人共进退,共话题,甚至共同上下班,在另...
    moitoije阅读 161评论 0 0