`

(五)NIO-总结

    博客分类:
  • NIO
nio 
阅读更多
一、代码总结

服务端
package com.study.nio.day3;

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

/**
 * NIO-ServerSocketChannel 服务端
 */
public class NIOServerDemo {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {

		// 1.创建服务端channel;设置非阻塞模式,默认为true;绑定端口,接收此端口发送的信息
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		serverSocketChannel.configureBlocking(false);
		serverSocketChannel.socket().bind(new InetSocketAddress(9999));
		
		// 2.创建选择器;将通道注册到选择器上;
		// 已注册集合
		Selector selector = Selector.open();
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		
		// 3.服务器处于开通状态,等待客户端连接,并处理客户端的请求并响应客户端
		while(true){
			
			// 已可以接收请求的channel的数量
			// 已就绪集合
			int readyCount = selector.select();
			if(readyCount > 0){ // 可以工作
				
				Iterator iterator = selector.selectedKeys().iterator();
				while(iterator.hasNext()){
					
					SelectionKey selectionKey = (SelectionKey) iterator.next();
					if(selectionKey.isAcceptable()){
						
						ServerSocketChannel serverSocketChannelAccept = (ServerSocketChannel) selectionKey.channel();
						SocketChannel socketChannel = serverSocketChannelAccept.accept();
						socketChannel.configureBlocking(false);
						socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
						
					}else if(selectionKey.isReadable()){
						
						SocketChannel readableChannel = (SocketChannel) selectionKey.channel();
						readableChannel.configureBlocking(false);
						
						String content = NIOUtil.read(readableChannel);
						System.out.println("服务端接收"+"客户端"+readableChannel.socket().getInetAddress().getHostAddress()+"发送的信息:"+content);
					
					}else if(selectionKey.isWritable()){
						
						SocketChannel writeableChannel = (SocketChannel) selectionKey.channel();
						writeableChannel.configureBlocking(false);
						
						String content = "服务端"+writeableChannel.socket().getInetAddress().getHostAddress()+"接收到客户端的信息" ;
						NIOUtil.write(writeableChannel, content);
						
						writeableChannel.register(selector, NIOUtil.cancel(selectionKey, SelectionKey.OP_WRITE));
					}
					iterator.remove();
				}
			}
		}
	}

}



客户端
package com.study.nio.day3;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class NIOClientDemo {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {

		SocketChannel socketChannel = SocketChannel.open();
		socketChannel.configureBlocking(false);
		socketChannel.connect(new InetSocketAddress("127.0.0.1",9999));
		
		Selector selector = Selector.open();
		socketChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_WRITE | SelectionKey.OP_READ);
		
		while(true){
			int readyCount = selector.select();
			if(readyCount > 0){
				Iterator iterator = selector.selectedKeys().iterator();
				while(iterator.hasNext()){
					SelectionKey selectionKey = (SelectionKey) iterator.next();
					// 得到的channel即为注册的channel
					SocketChannel socketChannelKey = (SocketChannel) selectionKey.channel();
					socketChannelKey.configureBlocking(false);
					
					if(selectionKey.isConnectable()){
						// 完成连接
						socketChannel.finishConnect();
					}else if(selectionKey.isWritable()){
											
						String content = "NIO LEARNING FINISH ! NIO 学习总结" ;
						NIOUtil.write(socketChannelKey, content);
						
						socketChannel.register(selector, NIOUtil.cancel(selectionKey, SelectionKey.OP_WRITE));
					}	else if(selectionKey.isReadable()){
						
						String content = NIOUtil.read(socketChannelKey);
						System.out.println("客户端接收"+"服务端"+socketChannelKey.socket().getInetAddress().getHostAddress()+"响应的信息:"+content);
					
					}
					iterator.remove();
				}
			}
			
		}
	}

}



工具类
package com.study.nio.day3;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;

/**
 * NIO工具类
 * @description
 * 避免粘包问题,约定发送与接收数据格式为:
 * 写入:content.getBytes("utf-8").length+"\r\n"+content
 * 读取:以"\r\n"为分割,头部为数据长度,尾部为数据内容
 * 注意read 和 writer方法都无法保证是否完整的读取或写出,需要循环检查
 * while(byteBuffer.hasRemaining())
 */
public class NIOUtil {

	private static final String DEFAULT_CODED_FORMAT = "UTF-8" ;
	
	public static String read(SocketChannel socketChannel) throws IOException{
		
		int contentLength = readContentHead(socketChannel);
		return readContentTail(socketChannel, contentLength) ;
	}

	/**
	 * 读取内容的头部信息
	 * @description
	 * 处理逻辑:
	 * 建立大小为1的缓冲区
	 * 每次读入一个字符
	 * 若不是以\r\n结尾,则继续读入
	 * 				   否则结束,此时读取的结果为number\r\n 
	 * @param socketChannel
	 * @return
	 * @throws IOException
	 */
	private static int readContentHead(SocketChannel socketChannel) throws IOException{
		
		String contentHead = "" ;
		ByteBuffer temp = ByteBuffer.allocate(1);
		while(!contentHead.endsWith("\r\n")){
			socketChannel.read(temp);
			contentHead += new String(temp.array(),DEFAULT_CODED_FORMAT);
			temp.clear();
		}
		int contentLenth = Integer.valueOf(contentHead.substring(0, contentHead.length()-2)).intValue();
		return contentLenth;
	}
	
	private static String readContentTail(SocketChannel socketChannel,int contentLength) throws IOException{
		ByteBuffer byteBuffer = ByteBuffer.allocate(contentLength);
		while(byteBuffer.hasRemaining()){
			socketChannel.read(byteBuffer);
		}
		return new String(byteBuffer.array(),DEFAULT_CODED_FORMAT);
	}
	
	/**
	 * 写入数据
	 * @param socketChannel
	 * @param content
	 * @throws IOException
	 */
	public static void write(SocketChannel socketChannel ,String content) throws IOException{
		StringBuffer sb = new StringBuffer();
		sb.append(content.getBytes(DEFAULT_CODED_FORMAT).length+"").append("\r\n").append(content);
		ByteBuffer byteBuffer = ByteBuffer.wrap(sb.toString().getBytes(DEFAULT_CODED_FORMAT));
		while(byteBuffer.hasRemaining()){
			socketChannel.write(byteBuffer);
		}
	}
	
	/**
	 * 取消某op
	 * @param selecttionKey
	 * @param op
	 * @return
	 */
	public static int cancel(SelectionKey selecttionKey, int op){
		int ops = selecttionKey.interestOps();
		return ops & ~op ;
	}
}



二、IO方式
  • 阻塞/非阻塞:是从线程的角度来考虑的,考虑线程是不是被挂起的状态
  • 同步/异步:是从逻辑执行的角度来考虑的,考虑程序在处理一段逻辑时可否并行处理另一端逻辑


  • BIO -- jdk1.0 -- BlockingIO -- 同步阻塞式IO -- 面向流操作字节字符 -- 单向传输
  • NIO -- jdk1.4 -- NonBlockingIO -- 同步非阻塞式IO -- 面向通道操作缓冲区 -- 双向传输
  • AIO -- jdk1.7 -- AnsyncronizeIO -- 异步非阻塞式IO -- 大量的使用回调函数实现了异步IO操作


三种方式,各有优缺点,使用时考虑具体的应用场景。

如:上传下载文件时,若并发量大,则不可以用NIO,因为是同步处理,就会出现等待。




分享到:
评论

相关推荐

    NIO学习总结

    五、NIO源码分析 对于NIO的源码,我们可以深入研究`Selector`、`SelectionKey`、`SelectorProvider`等关键类的实现,理解其内部的工作原理。此外,还可以关注`java.nio.channels`包下的各种通道类,如`FileChannel`...

    nio入门 IBM教材,pdf格式

    #### 五、作者简介 - **Greg Travis**:一位自由 Java 程序员和技术撰稿人,具有丰富的编程经验和广泛的兴趣领域。他是 Manning Publications 出版的《JDK 1.4 Tutorial》一书的作者,也是本教程的主要撰写者。 ##...

    Java NIO系列教程(一) Java NIO 概述

    #### 五、案例分析 假设我们正在开发一个简单的聊天服务器,用户可以连接到服务器并通过服务器相互发送消息。在这种情况下,我们可以利用Selector来监听多个客户端连接上的读写事件。当一个客户端发送消息时,...

    JAVA IO-NIO 详解

    #### 五、Channel妙用 **1. Channel的分类** - **FileChannel**: 用于文件的读写操作。 - **SocketChannel**: 用于网络套接字的读写操作。 - **DatagramChannel**: 用于UDP数据报的读写操作。 **2. 使用Channel**...

    NIO trick and trap .pdf

    ### NIO陷阱与解读 #### 一、NIO概述及变迁 ...总结,NIO虽然带来了显著的性能提升,但也伴随着一系列挑战。开发者需充分了解其内部机制,并结合具体的应用场景选择合适的设计方案和技术栈,才能真正发挥出NIO的优势。

    Java-NIO类库Selector机制解析.docx

    五、多路复用 多路复用是NIO类库中的一个核心概念,用于实现多个I/O操作的集中管理。多路复用可以看作是一个高效的I/O模式,用于提高I/O操作的性能。多路复用可以使用Selector机制来实现,Selector可以管理多个...

    Java NIO的介绍及工作原理

    #### 五、总结 Java NIO是一种更为高效和灵活的I/O处理方式,它通过Buffer、Channel、Selector和SelectionKey等核心组件实现了并发的非阻塞型I/O能力。相比于传统的阻塞I/O模型,NIO能够显著提高处理大量并发连接的...

    Java NIO 电子书

    - **第五章:正则表达式** - 5.1 正则表达式基础 - 介绍了正则表达式的概念及其基本语法。 - 5.2 Java 正则表达式 API - 讲解了 Java 中用于处理正则表达式的 API。 - 5.3 字符串类中的正则表达式方法 - 展示...

    Pro Java 7 NIO2

    #### 五、总结 通过对《Pro Java 7 NIO2》中Path类的学习,我们可以看到NIO.2 API为Java开发者提供了强大而灵活的文件系统操作工具。从简单的路径构建到复杂的文件属性访问,Path类及其相关API为Java程序提供了处理...

    Java NIO框架Netty教程.pdf

    #### 五、总结 Netty是一个功能强大且高度可定制的网络编程框架。通过本教程,我们不仅了解了Netty的基础概念,还通过实际代码示例学习了如何使用Netty构建一个简单的服务器和客户端应用程序。这对于理解Netty的...

    java NIO 详细讲解

    #### 五、高级特性 NIO还包括了一些高级特性,如非阻塞I/O、选择器(Selector)等,这些特性进一步增强了NIO的性能和灵活性。 - **非阻塞I/O**:允许用户在不等待的情况下继续执行其他任务,提高了程序的并发处理...

    Java NIO教程文档

    #### 五、非阻塞 IO 的使用 Java NIO 支持非阻塞模式,使得线程在等待 IO 操作时可以执行其他任务。 ```java SocketChannel channel = SocketChannel.open(new InetSocketAddress("localhost", 8080)); channel....

    Java Nio ibm技术文档

    #### 五、高级特性 ##### 5.1 异步I/O - **实现机制**:通过使用AsynchronousFileChannel和CompletionHandler等类来实现。 - **示例代码**: ```java AsynchronousFileChannel fileChannel = ...

Global site tag (gtag.js) - Google Analytics