Netty简单实例

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

服务端

package com.ninemax.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;

@SuppressWarnings("all")
public class SimpleChatServer {

	private static int port = 8080;

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

	public void run() throws Exception {
		// 用来处理I/O操作的多线程事件循环器
		// 用来接收进来的连接
		EventLoopGroup bossGroup = new NioEventLoopGroup();
		// 用来处理已经被接收的连接
		EventLoopGroup workerGroup = new NioEventLoopGroup();

		try {
			// 一个启动NIO服务的辅助启动类
			ServerBootstrap b = new ServerBootstrap();
			b.group(bossGroup, workerGroup)
					// 用来接收新的连接
					.channel(NioServerSocketChannel.class)
					// 目的是帮助使用者配置一个新的Channel
					.childHandler(new SimpleChatServerInitializer())
					// 提供给NioServerSocketChannel用来接收进来的连接
					.option(ChannelOption.SO_BACKLOG, 128)
					// 提供给由父管道ServerChannel接收到的连接
					.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 close!!!");
		}
	}

	public static void main(String[] args) throws Exception {
		
		if (args.length > 0) {
            port = Integer.parseInt(args[0]);
        } else {
            port = 8080;
        }
		new SimpleChatServer(port).run();
	}
}

服务端初始化

package com.ninemax.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;

public class SimpleChatServerInitializer extends ChannelInitializer {

	@Override
	protected 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());
		// 远程IP地址 ch.remoteAddress();
		System.out.println("client" + ch.remoteAddress() + "连接上");
	}

}

服务端处理器

package com.ninemax.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;

public class SimpleChatServerHandler extends SimpleChannelInboundHandler {

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

	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.add(ctx.channel());
	}
	
	//优先级高于messageReceived方法,有了这个方法就会屏蔽messageReceived方法
	/***
	 * 这里我们覆盖了chanelRead()事件处理方法。
	 * 每当从客户端收到新的数据时,
	 * 这个方法会在收到消息时被调用,
	 * 这个例子中,收到的消息的类型是ByteBuf
	 * @param ctx 通道处理的上下文信息
	 * @param msg 接收的消息
	 */
//	@Override
//	public void channelRead(ChannelHandlerContext ctx, String 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");
//			}
//		}
//	}
	/**
     * channelActive()方法将会在连接被建立并且准备进行通信时被调用。
     *
     * @param ctx
     */
	@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){
               channel.writeAndFlush("[" + incoming.remoteAddress() + "] " + msg + "\n");
		   }else {
			   // 缓冲区中数据强行输出
               channel.writeAndFlush("server: " + msg + "\n");
		   }
	   }
	}
	
	/***
     * 这个方法会在发生异常时触发
     * @param ctx
     * @param cause
     */
	@Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        Channel incoming = ctx.channel();
        System.out.println("client "+incoming.remoteAddress()+" 异常");
        // 当出现异常就关闭连接
        cause.printStackTrace();
        ctx.close();
    }

}

客户端

package com.ninemax.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;

@SuppressWarnings("all")
public class SimpleChatClient {
	// IP
	private static String host = "localhost";
	// 端口
	private static int port = 8080;
	// 构造函数
	public SimpleChatClient(String host, int port) {
		this.host = host;
		this.port = port;
	}

	public void run() throws Exception {
		// 用来处理I/O操作的多线程事件循环器
		EventLoopGroup group = new NioEventLoopGroup();
		try {
			Bootstrap bootstrap = new Bootstrap()
					.group(group)
					.channel(NioSocketChannel.class)
					.handler(new SimpleChatClientInitializer());
			//用connect()方法代替了bind()方法
			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();
				}
			}
		} finally {
			group.shutdownGracefully();
		}
	}
	
	public static void main(String[] args) throws Exception {
		new SimpleChatClient(host, port).run();
	}
}

客户端初始化

package com.ninemax.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;

public class SimpleChatClientInitializer extends ChannelInitializer{

	@Override
	protected 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());
	}

}

客户端处理器

package com.ninemax.netty;

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

public class SimpleChatClientHandler extends SimpleChannelInboundHandler {

	protected void messageReceived(ChannelHandlerContext ctx, String msg)
			throws Exception {
		System.out.println(msg);
	}

//	@Override
//	protected void channelRead(ChannelHandlerContext ctx, String msg)
//			throws Exception {
//		System.out.println(msg);
//	}

}

运行结果图

client01

Netty简单实例_第1张图片

client02

Netty简单实例_第2张图片

server

Netty简单实例_第3张图片

流程:

1.服务端SimpleChatServer启动

2.客户端SimpleChatClient启动

2.1.调用SimpleChatServerInitializer类的initChannel()方法

2.2.调用SimpleChatServerHandler类的channelActive()方法

3.当客户端输出的时候,调用SimpleChatServerHandler类messageReceived()方法

4.当客户端再启动一个线程的时候,依然调用第2步,然后会再调用SimpleChatServerHandler类的handlerAdded方法()

5.当客户端停止服务的时候,调用SimpleChatServerHandler类的channelInactive()和handlerRemoved()方法

总结:

服务端调用initChannel(),channelActive(),channelInactive()方法

客户端调用服务端hanlerAdded(),messageReceived(),handlerRemoved()方法

转载于:https://my.oschina.net/Tsher2015/blog/1514245

你可能感兴趣的:(Netty简单实例)