netty

上一篇,介绍了netty服务端简单的创建

下面介绍 客户端简单的创建

# netty 客户端(续上一篇)

创建 Client

package cn.edut.client;

import java.net.InetSocketAddress;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;

public class Client {

	public static void main(String[] args) {

		// 服务类
		ClientBootstrap bootstrap = new ClientBootstrap();

		// 线程池
		ExecutorService bossExecutor = Executors.newCachedThreadPool();
		ExecutorService workerExecutor = Executors.newCachedThreadPool();

		// socket工厂
		bootstrap.setFactory(new NioClientSocketChannelFactory(bossExecutor, workerExecutor));

		// 管道工厂
		bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
			@Override
			public ChannelPipeline getPipeline() throws Exception {
				ChannelPipeline pipeline = Channels.pipeline();
				pipeline.addLast("decoder", new StringDecoder());
				pipeline.addLast("encoder", new StringEncoder());
				pipeline.addLast("hiHandler", new HiHandler());
				return pipeline;
			}
		});
		
		// 连接服务端
		ChannelFuture connect = bootstrap.connect(new InetSocketAddress("127.0.0.1",10101));
		Channel channel = connect.getChannel();
		
		System.out.println("client start");
		
		Scanner scanner = new Scanner(System.in) ; 
		while(true) {
			System.out.println("请输入:");
			channel.write(scanner.nextLine()) ; 
		}
	}

}

完成 HiHandler (跟 HelloHandler 差不多,需要继承 SimpleChannelHandler)

package cn.edut.client;

import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;

public class HiHandler extends SimpleChannelHandler {
	@Override
	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
		System.out.println("messageReceived");
		System.out.println("MessageEvent:" + e);

		// 获取服务端信息
		String message = (String) e.getMessage();
		System.out.println("message:" + message);


		super.messageReceived(ctx, e);
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
		System.out.println("exceptionCaught");
		super.exceptionCaught(ctx, e);
	}

	@Override
	public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
		System.out.println("channelConnected");
		super.channelConnected(ctx, e);
	}

	@Override
	public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
		System.out.println("channelDisconnected");
		super.channelDisconnected(ctx, e);
	}

	@Override
	public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
		System.out.println("channelClosed");
		super.channelClosed(ctx, e);
	}
}

## 直接启动

不启动服务端,直接启动客户单

我们看下打印

因为没有创立连接 ,因此 channelDisconnected 没有被打印

而是打印了 channelClosed

因为出现了异常,因此 exceptionCaught 被打印

最后抛出异常 java.net.ConnectException: Connection refused: no further information: /127.0.0.1:10101

## 启动服务器,再启动

客户端连接


客户端发数据

客户端断开

# 源码分析

netty 在 nio 基础上, 做了两件事

  • 开启多个 selector ,对 selector 进行分区管理(workers)
  • 在 大门(端口监听)那里,单独创建 selector 管理(boss)

(如下图)