【Netty】netty5.x入门小程序解析

前言

        Netty是什么,简而言之,Netty就是一个高性能、事件驱动的异步的非堵塞的IO(NIO)框架,本是JBoss做的一个Jar包,用于快速开发高性能、高可靠性的网络服务器和客户端程序,通俗来讲,就是一个处理Socket的工具。更多讨论详见知乎https://www.zhihu.com/question/24322387。接下来我们从简单的入门程序开始了解一下Netty。

服务端

package com.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
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.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

/**
 * netty5服务端
 * @author -师德帅-
 *
 */
public class Server {

	public static void main(String[] args) {
		//服务类
		ServerBootstrap bootstrap = new ServerBootstrap();
		
		//boss和worker,两个线程池
		EventLoopGroup boss = new NioEventLoopGroup();
		EventLoopGroup worker = new NioEventLoopGroup();
		
		try {
			//设置线程池
			bootstrap.group(boss, worker);
			
			//设置socket工厂
			bootstrap.channel(NioServerSocketChannel.class);
			
			//设置管道工厂
			bootstrap.childHandler(new ChannelInitializer<Channel>() {

				@Override
				protected void initChannel(Channel ch) throws Exception {
					ch.pipeline().addLast(new StringDecoder());//解码器(包中自带)
					ch.pipeline().addLast(new StringEncoder());//编码器(包中自带)
					ch.pipeline().addLast(new ServerHandler());//处理消息的Handler(需创建)
				}
			});
			
			//设置参数,TCP参数
			bootstrap.option(ChannelOption.SO_BACKLOG, 2048);//serverSocketchannel的设置,链接缓冲池的大小
			bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);//socketchannel的设置,维持链接的活跃,清除死链接
			bootstrap.childOption(ChannelOption.TCP_NODELAY, true);//socketchannel的设置,关闭延迟发送
			
			//绑定端口
			ChannelFuture future = bootstrap.bind(10101);
			
			System.out.println("服务端启动。");
			
			//等待服务端关闭
			future.channel().closeFuture().sync();
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			//释放资源
			boss.shutdownGracefully();
			worker.shutdownGracefully();
		}
	}
}

对应的ServerHandler类

package com.server;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
 * 服务端消息处理
 * @author -师德帅-
 *
 */
public class ServerHandler extends SimpleChannelInboundHandler<String> {

	@Override
	protected void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {

		System.out.println(msg);
		//回写数据,收到客户端发来的消息之后,回写给客户端
		//这两种方式的效果相同ctx.channel().writeAndFlush("你好,我是服务端回复的消息。");
		ctx.writeAndFlush("你好,我是服务端回复的消息。");
	}

	/**
	 * 新客户端接入
	 */
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		System.out.println("channelActive");
	}

	/**
	 * 客户端断开
	 */
	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		System.out.println("channelInactive");
	}

	/**
	 * 异常
	 */
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		cause.printStackTrace();
	}
	
	
}

客户端

package com.client;

import java.io.BufferedReader;
import java.io.InputStreamReader;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

/**
 * netty5的客户端
 * @author -师德帅-
 *
 */
public class Client {

	public static void main(String[] args) {
		//服务类
		Bootstrap bootstrap = new Bootstrap();
		
		//worker线程池
		EventLoopGroup worker = new NioEventLoopGroup();
		
		try {
			//设置线程池,他不需要监听客户端连接,所以只需要设置worker就可以了
			bootstrap.group(worker);
			
			//设置socket工厂
			bootstrap.channel(NioSocketChannel.class);
			
			//设置管道
			bootstrap.handler(new ChannelInitializer<Channel>() {

				@Override
				protected void initChannel(Channel ch) throws Exception {
					ch.pipeline().addLast(new StringDecoder());//同服务端
					ch.pipeline().addLast(new StringEncoder());
					ch.pipeline().addLast(new ClientHandler());
				}
			});
			//连接服务端
			ChannelFuture connect = bootstrap.connect("127.0.0.1", 10101);
			//获取控制台录入
			BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
			while(true){
				System.out.println("请输入:");
				String msg = bufferedReader.readLine();//单行读取控制台输入
				connect.channel().writeAndFlush(msg);//将控制台输入发送到服务端
			}
			
		} catch (Exception e) {
			 e.printStackTrace();
		} finally{
			worker.shutdownGracefully();
		}
	}
}

同理,有一个ClientHandler

package com.client;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
 * 客户端消息处理
 * @author -师德帅-
 *
 */
public class ClientHandler extends SimpleChannelInboundHandler<String> {

	@Override//客户端收到消息之后需要调用的方法
	protected void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
		System.out.println("客户端收到消息:"+msg);
	}

}

测试

        启动服务端与客户端,在客户端的控制台输入一行字符,enter,这时,服务器端会接收到该客户端发来的消息并回写数据给客户端。


总结

        这个入门的小程序虽然不是很难,每步的作用在注释中也有体现,具体为什么要做这些步骤,我们就要分析netty 的源码了。在实际运用中,还要注意很多地方,比如,粘包问题,socket攻击等,相比之下,netty的可取之处还是非常多的,具体它的优点可以参考前言中给出的链接,详细介绍了netty框架的种种优点。

猜你喜欢

转载自blog.csdn.net/sds15732622190/article/details/78561718
今日推荐