`
北落有鱼
  • 浏览: 889 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

【Netty权威指南读书笔记】NIO通信模型

 
阅读更多

  1、缓冲区Buffer

  在NIO库中,所有数据都是用缓冲区(Buffer)处理的。缓冲区实质上是一个数组,通常它是一个字节数组(ByteBuffer),也可以使用其他种类的数组。但是一个缓冲区不仅仅是一个数组,缓冲区提供了对数据的结构化访问以及维护读写位置(limit、position)等信息。

  2、通道Channel

  Channel是一个通道,可以通过它读取和写入数据。通道与流的不同之处在于通道是双向的,流只是一个方向上移动(一个流必须是InputStream或者OutputStream的子类),而且通道可以同时用于读写。

  3、多路复用器Selector

  多路复用器提供选择已经就绪的任务的能力。简单来讲,Selector会不断地轮询注册在其上的Channel,如果某个Channel上面有新的TCP连接接入、读和写事件,这个Channel就处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以获得就绪Channel的集合,进行后续的I/O操作。

  介绍完NIO几个核心概念,下面来看看服务端与客户端的通信序列图,并用NIO实现一个EchoServer,以对整个流程有更好的理解。



 

package io.nio;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioEchoServer {

	public static void main(String[] args) {
		MultiplexerEchoServer server = new MultiplexerEchoServer(8080);
		new Thread(server).start();
		new Thread(new Power(server)).start();
	}

	private static class MultiplexerEchoServer implements Runnable {

		private Selector selector;
		private ServerSocketChannel server;
		private volatile boolean running;

		public MultiplexerEchoServer(int port) {
			try {
				running = true;
				selector = Selector.open();
				server = ServerSocketChannel.open();
				server.configureBlocking(false);
				server.socket().bind(new InetSocketAddress(port), 1024);
				server.register(selector, SelectionKey.OP_ACCEPT);
				System.out.println("Server start in:" + port);
			} catch (IOException e) {
				e.printStackTrace();
				System.exit(1);
			}
		}

		public void stop() {
			running = false;
		}

		@Override
		public void run() {
			while (running) {
				try {
					selector.select(1000);
					Set<SelectionKey> readyKeys = selector.selectedKeys();
					Iterator<SelectionKey> it = readyKeys.iterator();
					SelectionKey key = null;
					while (it.hasNext()) {
						key = it.next();
						it.remove();
						try {
							handle(key);
						} catch (Exception e) {
							if (key != null) {
								key.cancel();
								if (key.channel() != null) {
									key.channel().close();
								}
							}
						}
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		private void handle(SelectionKey key) throws IOException {
			if (key.isValid()) {
				if (key.isAcceptable()) {
					ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
					SocketChannel sc = ssc.accept();
					sc.configureBlocking(false);
					sc.register(selector, SelectionKey.OP_READ);
				}
				if (key.isReadable()) {
					SocketChannel sc = (SocketChannel) key.channel();
					ByteBuffer buffer = ByteBuffer.allocate(1024);
					int readBytes = sc.read(buffer);
					// 大于0:读到了字节、0:没有读到字节、-1:链路已经关闭
					if (readBytes > 0) {
						buffer.flip();
						byte[] bytes = new byte[buffer.remaining()];
						buffer.get(bytes);
						String msg = new String(bytes, "UTF-8");
						System.out.println("Server received:" + msg);
						doWrite(sc, msg);
					} else if (readBytes < 0) {
						key.cancel();
						sc.close();
					}

				}
			}
		}

		private void doWrite(SocketChannel channel, String response) throws IOException {
			if (response != null && response.trim().length() > 0) {
				byte[] bytes = response.getBytes();
				ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
				buffer.put(bytes);
				buffer.flip();
				channel.write(buffer);
			}
		}

	}

	private static class Power implements Runnable {

		private MultiplexerEchoServer server;

		public Power(MultiplexerEchoServer server) {
			this.server = server;
		}

		@Override
		public void run() {
			BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
			try {
				String msg = in.readLine();
				while (msg != null && !"shutdown".equalsIgnoreCase(msg)) {
					msg = in.readLine();
				}
				server.stop();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

}

 

 

 

 

package io.nio;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioEchoClient {

	public static void main(String[] args) {
		EchoClient client = new EchoClient("127.0.0.1", 8080);
		new Thread(client).start();
		new Thread(new Writer(client)).start();
	}

	private static class EchoClient implements Runnable {

		private String host;
		private int port;
		private Selector selector;
		private SocketChannel client;
		private volatile boolean running;

		public EchoClient(String host, int port) {
			try {
				this.running = true;
				this.host = host == null ? "127.0.0.1" : host;
				this.port = port;
				this.selector = Selector.open();
				this.client = SocketChannel.open();
				client.configureBlocking(false);
			} catch (IOException e) {
				e.printStackTrace();
				System.exit(1);
			}
		}

		@Override
		public void run() {
			try {
				doConnect();
			} catch (IOException e) {
				e.printStackTrace();
				System.exit(1);
			}
			while (running) {
				try {
					selector.select(1000);
					Set<SelectionKey> readyKeys = selector.selectedKeys();
					Iterator<SelectionKey> it = readyKeys.iterator();
					SelectionKey key = null;
					while (it.hasNext()) {
						key = it.next();
						it.remove();
						try {
							handle(key);
						} catch (Exception e) {
							e.printStackTrace();
							if (key != null) {
								key.cancel();
								if (key.channel() != null) {
									key.channel().close();
								}
							}
							System.exit(1);
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
					System.exit(1);
				}
			}
			if (selector != null) {
				try {
					selector.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		private void handle(SelectionKey key) throws IOException {
			if (key.isValid()) {
				SocketChannel sc = (SocketChannel) key.channel();
				if (key.isConnectable()) {
					if (sc.finishConnect()) {
						sc.register(selector, SelectionKey.OP_READ);
					} else {
						System.exit(1);
					}
				}
				if (key.isReadable()) {
					ByteBuffer buffer = ByteBuffer.allocate(1024);
					int readBytes = sc.read(buffer);
					// 大于0:读到了字节、0:没有读到字节、-1:链路已经关闭
					if (readBytes > 0) {
						buffer.flip();
						byte[] bytes = new byte[buffer.remaining()];
						buffer.get(bytes);
						String msg = new String(bytes, "UTF-8");
						System.out.println("Client received:" + msg);
					} else if (readBytes < 0) {
						key.cancel();
						sc.close();
					}
				}
			}
		}

		private void doConnect() throws IOException {
			if (client.connect(new InetSocketAddress(host, port))) {
				client.register(selector, SelectionKey.OP_READ);
			} else {
				client.register(selector, SelectionKey.OP_CONNECT);
			}
		}

		public void doWrite(String msg) {
			byte[] bytes = msg.getBytes();
			ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
			buffer.put(bytes);
			buffer.flip();
			try {
				client.write(buffer);
				System.out.println("Cliend send:" + msg);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		public void stop() {
			running = false;
		}
	}

	private static class Writer implements Runnable {

		private EchoClient client;

		public Writer(EchoClient client) {
			this.client = client;
		}

		@Override
		public void run() {
			BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
			try {
				String msg = in.readLine();
				while (msg != null && !"quit".equalsIgnoreCase(msg)) {
					client.doWrite(msg);
					msg = in.readLine();
				}
				client.stop();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

 

  • 大小: 67.2 KB
  • 大小: 80.6 KB
分享到:
评论

相关推荐

    java_Netty权威指南,详解nio,tcp,http,netty

    java_Netty权威指南,详解nio,tcp,http,netty.rar

    netty权威指南 第1版(李林峰) + 源码

    《Netty权威指南》第1版 是异步非阻塞通信领域的经典之作,基于最新版本Netty 5.0编写,是国内首本深入介绍Netty原理和架构的技术书籍,也是作者多年实战经验的总结和浓缩。在理论方面,讲解了Netty的逻辑架构模型和...

    Netty权威指南PDF书籍

    Netty权威指南,可供IT开发者以及正在学习的同学提供学习资料,Netty权威指南PDF书籍

    Netty权威指南完整版高清pdf

    Netty权威指南完整版高清pdf 完整版

    netty权威指南 第2版(李林峰) + 源码

    , 《Netty权威指南》适合架构师、设计师、软件开发工程师、测试人员和其他对Java NIO框架、Java通信感兴趣的相关人士阅读,相信通过学习《Netty权威指南》,能够熟悉和掌握Netty这一优秀的异步通信框架,实现高可用...

    Netty权威指南(第2版)

    《Netty 权威指南(第2 版)》适合架构师、设计师、软件开发工程师、测试人员以及其他对Java NIO 框架、Netty 感兴趣的相关人士阅读,通过《Netty 权威指南(第2 版)》的学习,读者不仅能够掌握Netty 基础功能的...

    Netty权威指南 PDF电子书下载 带目录书签 完整版

    Netty权威指南 PDF电子书下载 带目录书签 完整版 Netty权威指南 PDF电子书下载 带目录书签 完整版 高清

    Netty权威指南高清完整版PDF

    《Netty权威指南》适合架构师、设计师、软件开发工程师、测试人员和其他对Java NIO框架、Java通信感兴趣的相关人士阅读,相信通过学习《Netty权威指南》,能够熟悉和掌握Netty这一优秀的异步通信框架,实现高可用...

    Netty权威指南第二版

    《Netty 权威指南(第2 版)》适合架构师、设计师、软件开发工程师、测试人员以及其他对JavaNIO 框架、Netty 感兴趣的相关人士阅读,通过《Netty 权威指南(第2 版)》的学习,读者不仅能够掌握Netty 基础功能的使用...

    Z00317 NETTY权威指南(第2版)

    Z00317 NETTY权威指南(第2版)

    Netty权威指南(第二版)

    Netty权威指南中文第二版本,可进一步了解Netty的技术细节

    Netty权威指南 第2版 带书签目录 完整版

    Netty权威 第2版 带书签目录 RPC dubbo Netty权威 第2版 带书签目录 RPC dubbo Netty权威 第2版 带书签目录 RPC dubbo Netty权威 第2版 带书签目录 RPC dubbo Netty权威 第2版 带书签目录 RPC dubbo Netty权威 第2版...

    《Netty权威指南(第二版)》.pdf

    Netty权威指南第二版PDF

    Netty权威指南高清版本

    Netty权威指南学习工具书,帮你快速了解Netty开发,同时偏向实用性,有着很多的代码例子,可以帮你快速了解和应用

    netty权威指南

    , 《Netty权威指南》适合架构师、设计师、软件开发工程师、测试人员和其他对Java NIO框架、Java通信感兴趣的相关人士阅读,相信通过学习《Netty权威指南》,能够熟悉和掌握Netty这一优秀的异步通信框架,实现高可用...

    Netty权威指南 第2版 带书签目录 高清完整版.pdf

    《Netty 权威指南(第2 版)》适合架构师、设计师、软件开发工程师、测试人员以及其他对Java NIO 框架、Netty 感兴趣的相关人士阅读,通过《Netty 权威指南(第2 版)》的学习,读者不仅能够掌握Netty 基础功能的...

    Netty权威指南pdf+源代码

    Netty权威指南高清版pdf(带完整书签目录)+源代码 亲测可用

    Netty权威指南-Netty源码

    Netty权威指南源码

    netty权威指南 源码

    netty权威指南 官方源码 netty5.0 netty权威指南 官方源码 netty5.0

Global site tag (gtag.js) - Google Analytics