netty框架的学习


之前几天的话开始稍微熟悉了一点maven和Springboot框架,从今天开始要正式的开始学习netty框架了。

1.netty环境的搭建

要开始学习netty框架的开发的话,首先第一步就是要进行环境的搭建了,搭建netty开发环境很简单,只需要在maven项目中,导入下面这行依赖即可。

<dependency>
  <groupId>io.netty</groupId>
  <artifactId>netty-all</artifactId>
  <version>4.1.16.Final</version>
</dependency>

2.netty的特点

环境搭建好了之后,我现在还不能够正式的开始写程序,因为现在我对netty可以说是完全不了解,所以我们得先去了解netty。

2.1什么是netty

Netty是由JBOSS提供的一个java开源框架,现为 Github上的独立项目。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

也就是说,Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty相当于简化和流线化了网络应用的编程开发过程,例如:基于TCP和UDP的socket服务开发。

2.2为什么要使用netty

Netty有很多重要的特性,主要特性如下:

  • 优雅的设计
  • 统一的API接口,支持多种传输类型,例如OIO,NIO
  • 简单而强大的线程模型
  • 丰富的文档
  • 卓越的性能
  • 拥有比原生Java API 更高的性能与更低的延迟
  • 基于池化和复用技术,使资源消耗更低
  • 安全性
  • 完整的SSL/TLS以及StartTLS支持
  • 可用于受限环境,如Applet以及OSGI

3.netty框架的搭建

3.1创建一个maven项目

因为楼主后期主要是使用Springboot框架进行程序开发,所以这儿我们就直接创建一个maven项目来搭建测试netty,具体如何创建一个maven项目我们就不进行过多的一个赘述了。

在这里插入图片描述

然后在启动类的同级目录下创建一个包,包名称可以取名叫server,在这个包下面创建三个文件夹,用于存放netty相关配置类,一个是NettyTcpServer.Java,一个是ServerChannelHandler.java,这个里面就写netty的握手相关操作,一个是ServerChannelInitial.java。

最后创建的项目结构如图所示

这里项目报错应该是开发环境的原因,具体是哪里的原因我也还没找到,但是项目内部并没有报错。

这里我是将启动类的名称改掉了的。

3.2导入依赖

我们知道maven项目是需要导入外部依赖才能够正常运行的,这儿就直接贴出pom.xml文件里面的代码

<groupId>com.example.test</groupId>
<artifactId>netty</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>


<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.0.1.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	<java.version>1.8</java.version>
</properties>

<dependencies>
	<dependency>
		<groupId>io.netty</groupId>
		<artifactId>netty-all</artifactId>
		<version>5.0.0.Alpha2</version>
		<!-- <version>4.1.24.Final</version> -->
	</dependency>

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>

	<dependency>
		<groupId>org.mybatis.spring.boot</groupId>
		<artifactId>mybatis-spring-boot-starter</artifactId>
		<version>1.3.2</version>
	</dependency>

	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
	</plugins>
</build>

3.3搭建框架

这是我的启动类代码

package com.example.test.netty;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

import com.example.test.netty.server.NettyTcpServer;

import io.netty.channel.ChannelFuture;

/**
 * Hello world!
 *
 */
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class NettyApplication implements CommandLineRunner
{
	final NettyTcpServer nettyTcpServer;
	
	public NettyApplication(NettyTcpServer nettyTcpServer){
	    	this.nettyTcpServer = nettyTcpServer;
	    }
	
    public static void main( String[] args )
    {
       SpringApplication.run(NettyApplication.class, args);
    }

  
    
	public void run(String... args) throws Exception {
		// TODO Auto-generated method stub
		ChannelFuture startPLC = nettyTcpServer.start();
		startPLC.channel().closeFuture().syncUninterruptibly();
		
	}
}

NettyTcpServer.Java`

package com.example.test.netty.server;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PreDestroy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;



import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
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;
import io.netty.util.concurrent.Future;

@Component
public class NettyTcpServer {
	private static final Logger log = LoggerFactory.getLogger(NettyTcpServer.class);
	
	//boss事件轮询线程组    用来接收进来的连接
    private EventLoopGroup boss = new NioEventLoopGroup(1);
    //worker事件轮询线程组     用来处理已经被接收的连接
    private EventLoopGroup worker = new NioEventLoopGroup();
    
    private Integer portPLC=8083;
    
    private Channel channel;

    /**
     * 存储client的channel
     * key:ip,value:Channel
     */
    public static Map<String, Channel> map = new ConcurrentHashMap<String, Channel>();

    public static Map<String, Channel>  getChannes() {
    	return map;
    }

	public ChannelFuture start() {
		// TODO Auto-generated method stub
		  //启动类
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        //组配置,初始化ServerBootstrap的线程组
        serverBootstrap.group(boss, worker)
                ///构造channel通道工厂//bossGroup的通道,只是负责连接
                .channel(NioServerSocketChannel.class)
              //设置通道处理者ChannelHandlerworkerGroup的处理器
                .childHandler(new ServerChannelInitializer())
               
                //socket参数,当服务器请求处理程全满时,用于临时存放已完成三次握手请求的队列的最大长度。如果未设置或所设置的值小于1,Java将使用默认值50。
                .option(ChannelOption.SO_BACKLOG, 1024)
                //启用心跳保活机制,tcp,默认2小时发一次心跳
                .childOption(ChannelOption.SO_KEEPALIVE, true);
        //Future:异步任务的生命周期,可用来获取任务结果
        //绑定端口,开启监听,同步等待
        ChannelFuture channelFuture = serverBootstrap.bind(portPLC).syncUninterruptibly();
        if (channelFuture != null && channelFuture.isSuccess()) {
            //获取通道
            channel = channelFuture.channel();
            log.info("PLC server start success, port = {}", portPLC);
        } else {
            log.error("PLC server start fail");
        }
        return channelFuture;
		
	}
	
	 @PreDestroy
	    public void destroy() {
	        if (channel != null) {
	            channel.close();
	        }
	        try {
	            Future<?> future = worker.shutdownGracefully().await();
	            if (!future.isSuccess()) {
	                log.error("PLC workerGroup shutdown fail, {}", future.cause());
	            }
	            Future<?> future1 = boss.shutdownGracefully().await();
	            if (!future1.isSuccess()) {
	                log.error("PLC bossGroup shutdown fail, {}", future1.cause());
	            }
	        } catch (InterruptedException e) {
	            e.printStackTrace();
	        }
	        log.info("PLC server shutdown success");
	    }


	
	
	
}

ServerChannelHandler.java

package com.example.test.netty.server;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;



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




@ChannelHandler.Sharable
public  class ServerChannelHandler extends SimpleChannelInboundHandler<Object>{
	 private static final Logger log = LoggerFactory.getLogger(ServerChannelHandler.class);


	@Override
	public void channelRead(ChannelHandlerContext ctx, Object arg) throws Exception {
		log.info("tcp client " + ctx.channel().remoteAddress().toString() + "info:" + arg);
		
	}





	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		
		super.channelActive(ctx);
		log.info("tcp client " + ctx.channel().remoteAddress().toString() + " connect success");
	}


	@Override
	public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
		// TODO Auto-generated method stub
		super.close(ctx, promise);
	}
	@Override
	protected void messageReceived(ChannelHandlerContext arg0, Object arg1) throws Exception {
		// TODO Auto-generated method stub
		
	}	 	
}

ServerChannelInitializer.java

package com.example.test.netty.server;

import java.util.concurrent.TimeUnit;



import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
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.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;

public class ServerChannelInitializer extends ChannelInitializer<SocketChannel>  {

	 @Override
	    protected void initChannel(SocketChannel socketChannel) throws Exception {
	        ChannelPipeline pipeline = socketChannel.pipeline();
	        //ByteBuf delimiter = Unpooled.copiedBuffer("\r\n".getBytes());
	        //pipeline.addFirst(new DelimiterBasedFrameDecoder(2048*10, delimiter));
	        //IdleStateHandler心跳机制,如果超时触发Handle中userEventTrigger()方法
	        pipeline.addLast("idleStateHandler", new IdleStateHandler(15, 0, 0, TimeUnit.MINUTES));
	        //字符串解码器
	        pipeline.addLast(new StringDecoder() ,new StringEncoder());
	        //自定义Handler
	        pipeline.addLast(new ServerChannelHandler());

	    }
}

代码添加完之后运行启动类
在这里插入图片描述
控制台出现如上,说明服务端启动成功。

然后用调试工具进行客户端的测试
在这里插入图片描述
在调试工具中输入ip和端口点击打开,然后看开发工具控制台,如果有输出,就证明客户端成功连接。
在这里插入图片描述
上图就说明我这个项目客户端已经连接成功了。
然后我们再来测试一下,用客户端向服务端发送数据,看服务端能不能接收到数据。
我们在测试工具中,发送信息那一栏随便输入一点东西,然后点击发送
在这里插入图片描述
发送之后然后查看控制台有没有接收到打印出来
在这里插入图片描述
可以看到我这边控制台是打印出来了的。

这样差不多netty框架就搭建好了,在这里面就可以实现用户端与服务端之间数据的传导。如果我们以后要使用这个框架进行数据的处理的话,就可以直接在ServerChannelHandler.java里面的 channelRead和channelActive方法进行数据的处理。
在这里插入图片描述
差不多一个简单的netty框架就搭建好了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值