`
drluorose
  • 浏览: 5716 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java NIO 浅析

阅读更多

1. Java NIO初探

1.1 什么是IO

      I/O输入/输出(Input/Output),分为IO设备和IO接口两个部分。 在POSIX兼容的系统上,例如Linux系统,I/O操作可以有多种方式,比如DIO(Direct I/O),AIO(Asynchronous I/O 异步I/O),Memory-Mapped I/O(内存映设I/O)等,不同的I/O方式有不同的实现 方式和性能,在不同的应用中可以按情况选择不同的I/O方式。

      IO是主存和外部设备之间拷贝数据的过程。IO的实现是通过操作系统调用IO命令完成的。高级语言对这些IO命令加以封装形成IO api,应用程序通过调用这些api完成网络通信,文件存储,程序的输入输出等。

1.2 Java NIO

       Java NIO 是 Java New IO 的简称,实在jdk1.4版本之后提供的新的IO api。该api提供了无阻塞的io访问的实现方式。

       Sun 标榜的Java NIO特性如下:

        –     为所有的原始类型提供 (Buffer) 缓存支持。 

        –     字符集编码解码解决方案。

        –     Channel :一个新的原始 I/O 抽象。

        –     支持锁和内存映射文件的文件访问接口。

        –     提供多路 (non-bloking) 非阻塞式的高伸缩性网络 I/O

 

1.3 Java NIO 实战

         a)现在实用JAVA NIO实现一个文本文件拷贝的过程。

        

package org.cookie.nio;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

public class NIO {
	public static void main(String args[]) throws IOException {
		String filePathIn = "c:\\nio_test.sql";
		String filePathOut = "d:\\nio_test_n.txt";
		File fileOutN = new File("d:\\nio_test_nn.txt");
		File fileOut = new File(filePathOut);
		if (!fileOut.exists()) {
			fileOut.createNewFile();
		}
		if (!fileOutN.exists()) {
			fileOutN.createNewFile();
		}
		FileInputStream fileInputStream = new FileInputStream(filePathIn);
		FileOutputStream fileOutputStream = new FileOutputStream(filePathOut);

		FileOutputStream fileOutputStreamN = new FileOutputStream(fileOutN);

		
		FileChannel fileInputChannel = fileInputStream.getChannel(); //从文件流中拿到文件通道
		FileChannel fileOutputChannel = fileOutputStream.getChannel();
		FileChannel fileOutputChannelN = fileOutputStreamN.getChannel();

		ByteBuffer byteBuffer = ByteBuffer.allocate(1024);//建立一个缓存通道
		while (true) {
			byteBuffer.clear();//清空通道,byteBuffer变得可写
			int r = fileInputChannel.read(byteBuffer);//文件通道向byteBuffer读入数据
			if (r == -1) {
				break;
			}
			byteBuffer.flip();//环绕byteBuffer这时候可以将byteBuffer写入到文件通道中
			fileOutputChannel.write(byteBuffer);
			byteBuffer.flip();//byteBuffer通道可以实现重复读,在读之前需要调用byteBuffer的flip方法
			fileOutputChannelN.write(byteBuffer);
			byteBuffer.flip();
			System.out.println(byteBufferToString(byteBuffer));
		}
		fileInputStream.close();
		fileOutputStream.close();
		fileOutputStreamN.close();
	}

	public static String byteBufferToString(ByteBuffer buffer) {

		System.out.println("buffer=" + buffer);
		try {
			Charset charset = Charset.forName("UTF-8");//声明一个字符集
			CharBuffer charBuffer = charset.decode(buffer);//通过字符集对buffer进行编码
			System.out.println("charBuffer=" + charBuffer);
			System.out.println(charBuffer.toString());
			return charBuffer.toString();
		} catch (Exception ex) {
			ex.printStackTrace();
			return "";
		}
	}
}

 

       b) 通过 Java AIO实现一个简单的服务端,客户端通信

   JAVA NIO Server 端

    

package com.cookie.study.java;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;


public class HeartServerNIO {
	public static String decode(ByteBuffer byteBuffer){
		Charset charset = Charset.forName("UTF-8");
		CharBuffer  charBuffer = charset.decode(byteBuffer);
		return charBuffer.toString();
	}
	
    public static void main(String args[]) 
    { 
        try {
			Selector selector = Selector.open();//创建一个selector对象,selector是在Java网络aio中最重要的对象
			
			ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();//建立一个ServerSocketChannel
			serverSocketChannel.configureBlocking(false);//设置ServerSocketChannel为非阻塞的方式
			InetSocketAddress address = new InetSocketAddress(9000);
			serverSocketChannel.socket().bind(address);
			
			//注册Selector,通过SelectionKey.OP_ACCEPT
			SelectionKey selectionKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
			
			
			while (true){
			    int selectedNum = selector.select();//Selects a set of keys whose corresponding channels are ready for I/O operations. 翻译为:选取一下已经准备好IO操作的通道的SelectionKey
			    System.out.println("Selected Number is :"+selectedNum);
			    Iterator iter = selector.selectedKeys().iterator();//迭代SelectionKeys
			    
			    while(iter.hasNext()){
			        SelectionKey selectedKey = (SelectionKey)iter.next();
			        
			        if ((selectedKey.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT){// 处理OP_ACCEPT事件
			            ServerSocketChannel serverChannel = (ServerSocketChannel)selectedKey.channel();
			            SocketChannel socketChannel = serverChannel.accept();
			            socketChannel.configureBlocking(false);
			            
			            SelectionKey readKey = socketChannel.register(selector, SelectionKey.OP_READ);//注册OP_READ事件                    
			            iter.remove();               
			        }else if ( (selectedKey.readyOps()&SelectionKey.OP_READ) == SelectionKey.OP_READ ){//处理OP_READ事件
			            ByteBuffer buffer = ByteBuffer.allocate(1024);
			            SocketChannel socketChannel = (SocketChannel)selectedKey.channel();
			            while (true){
			                buffer.clear();
			                int i=socketChannel.read(buffer);//将socket数据读入byteBuffer中
			            
			                if (i == -1) break;
			                if (i == 0) break;
			            
			                buffer.flip();//环绕byteBuffer,准备读取buffer数据
			                socketChannel.write(buffer);
			                buffer.flip();//需要再次读取时,需要再次调用buffer的环绕方法
			                System.out.println(decode(buffer));
			            }
			            iter.remove();
			        }
			    }
			}
		} catch (ClosedChannelException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
}

   

 

    Java  NIO Client 端

   

package com.cookie.study.java;

import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
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 HeartClientNIO extends Frame {

	/* 标识数字 */
	private static int flag = 0;
	/* 缓冲区大小 */
	private static int BLOCK = 4096;
	/* 接受数据缓冲区 */
	private static ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);
	/* 发送数据缓冲区 */
	private static ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);
	/*
	 * 成员方法出场...
	 */
	private TextField tfText;
	private TextArea taContent;

	private TFListener tfListener = new TFListener();

	/**
	 * 注意,入口... ^^
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		new HeartClientNIO().launchFrame();
	}

	/**
	 * Loading GU
	 */
	public void launchFrame() {
		tfText = new TextField();
		taContent = new TextArea();
		this.setSize(300, 300);
		this.setLocation(300, 300);
		this.tfText.addActionListener(this.tfListener);
		this.add(tfText, BorderLayout.SOUTH);
		this.add(taContent, BorderLayout.NORTH);
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		this.pack();
		this.connect();
		this.setVisible(true);
	}

	/**
	 * 我在努力地连接服务器中...
	 */
	public void connect() {
		try {
			SocketChannel socketChannel = SocketChannel.open();
			socketChannel.configureBlocking(false);

			Selector selector = Selector.open();
			socketChannel.register(selector, SelectionKey.OP_CONNECT);
			InetSocketAddress inetSocketAddress = new InetSocketAddress(
					"localhost", 9000);
			socketChannel.connect(inetSocketAddress);

			this.tfListener.setSelector(selector);

			Set<SelectionKey> selectionKeys;
			Iterator<SelectionKey> iterator;
			SelectionKey selectionKey;
			SocketChannel client;
			String receiveText;
			String sendText;
			int count = 0;

			// 选择一组键,其相应的通道已为 I/O 操作准备就绪。
			// 此方法执行处于阻塞模式的选择操作。
			selector.select();
			// 返回此选择器的已选择键集。
			selectionKeys = selector.selectedKeys();
			System.out.println(selectionKeys.size());
			iterator = selectionKeys.iterator();
			while (iterator.hasNext()) {
				selectionKey = iterator.next();
				if (selectionKey.isConnectable()) {
					System.out.println("client connect");
					client = (SocketChannel) selectionKey.channel();
					// 判断此通道上是否正在进行连接操作。
					// 完成套接字通道的连接过程。
					if (client.isConnectionPending()) {
						client.finishConnect();
						System.out.println("完成连接!");
						sendbuffer.clear();
						sendbuffer.put("Hello,Server".getBytes("UTF-8"));
						sendbuffer.flip();
						client.write(sendbuffer);
					}
					client.register(selector, SelectionKey.OP_READ);
				}
			}
			selectionKeys.clear();
			new Thread(new ReadProcess(selector)).start();
			
		} catch (UnknownHostException e) {
			System.out.println("UnknownHostException");
			e.printStackTrace();
		} catch (IOException e) {
			System.out.println("IOException");
			e.printStackTrace();
		} finally {
			// 关闭啥尼...
		}

	}

	/**
	 * 额不会傻等着tfText(TextField tfText的监听器类)
	 */
	class TFListener implements ActionListener {
		private String str;
		private Selector selector;

		@Override
		public void actionPerformed(ActionEvent e) {
			str = tfText.getText().trim();
			tfText.setText("");

			try {
				if (selector != null) {
					selector.select();
					Set<SelectionKey> selectionKeys = selector.selectedKeys();
					Iterator<SelectionKey> iterator = selectionKeys.iterator();
					while (iterator.hasNext()) {
						SelectionKey selectionKey = iterator.next();
						if (selectionKey.isWritable()) {
							sendbuffer.clear();
							SocketChannel client = (SocketChannel) selectionKey.channel();
							String sendText = "message from client--" + (flag++)+str;
							sendbuffer.put(sendText.getBytes("UTF-8"));
							// 将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位
							sendbuffer.flip();
							client.write(sendbuffer);
							System.out.println("客户端向服务器端发送数据--:" + sendText);
							client.register(selector, SelectionKey.OP_READ);
						}
					}
					selectionKeys.clear();
				}
			} catch (ClosedChannelException e1) {
				e1.printStackTrace();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}

		public void setSelector(Selector selector) {
			this.selector = selector;
		}
	}
	
	public class ReadProcess implements Runnable{
		
		private Selector selector;
		
		public ReadProcess(Selector selector){
			this.selector = selector;
		}
		
		public void run() {
			while(true){
				try {
					selector.select();
					Set<SelectionKey>  selectionKeys = this.selector.selectedKeys();
					Iterator<SelectionKey> iterator = selectionKeys.iterator();
					while(iterator.hasNext()){
						SelectionKey selectionKey = iterator.next();
						if(selectionKey.isReadable()){
							SocketChannel client = (SocketChannel) selectionKey.channel();
							// 将缓冲区清空以备下次读取
							receivebuffer.clear();
							// 读取服务器发送来的数据到缓冲区中
							int count = client.read(receivebuffer);
							if (count > 0) {
								String receiveText = new String(receivebuffer.array(), 0,
										count,"UTF-8");
								System.out.println("客户端接受服务器端数据--:" + receiveText);
								taContent.setText(taContent.getText()+"\n"+receiveText);
								client.register(selector, SelectionKey.OP_WRITE);
							}
						}
					}
					selectionKeys.clear();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

 

 

       

 

 

      

 

 

 

分享到:
评论

相关推荐

    JavaNIO浅析IO模型Java开发Java经验技巧共1

    JavaNIO浅析IO模型Java开发Java经验技巧共10页.pdf.zip

    java NIO和java并发编程的书籍

    java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java...

    JavaNIO chm帮助文档

    Java NIO系列教程(一) Java NIO 概述 Java NIO系列教程(二) Channel Java NIO系列教程(三) Buffer Java NIO系列教程(四) Scatter/Gather Java NIO系列教程(五) 通道之间的数据传输 Java NIO系列教程(六)...

    java nio 包读取超大数据文件

    Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据...

    Java NIO英文高清原版

    Java NIO英文高清原版

    java NIO 中文版

    讲解了 JavaIO 与 JAVA NIO区别,JAVA NIO设计理念,以及JDK中java NIO中语法的使用

    java NIO.zip

    java NIO.zip

    Java NIO 中文 Java NIO 中文 Java NIO 中文文档

    Java NIO 深入探讨了 1.4 版的 I/O 新特性,并告诉您如何使用这些特性来极大地提升您所写的 Java 代码的执行效率。这本小册子就程序员所面临的有代表性的 I/O 问题作了详尽阐述,并讲解了 如何才能充分利用新的 I/O ...

    java NIO 视频教程

    Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式。 Java NIO: Channels and Buffers(通道和缓冲区) 标准的IO基于字节流和字符流进行操作的,...

    java nio 实现socket

    java nio 实现socketjava nio 实现socketjava nio 实现socketjava nio 实现socketjava nio 实现socket

    java nio中文版

    java NIO是 java New IO 的简称,在 jdk1.4 里提供的新 api 。 Sun 官方标榜的特性如下: – 为所有的原始类型提供 (Buffer) 缓存支持。 – 字符集编码解码解决方案。 – Channel :一个新的原始 I/O 抽象。 – 支持...

    Java Nio selector例程

    java侧起server(NioUdpServer1.java),基于Java Nio的selector 阻塞等候,一个android app(NioUdpClient1文件夹)和一个java程序(UI.java)作为两个client分别向该server发数据,server收到后分别打印收到的消息...

    基于Java NIO实现五子棋游戏.zip

    基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现...

    java NIO技巧及原理

    java NIO技巧及原理解析,java IO原理,NIO框架分析,性能比较

    java基于NIO实现Reactor模型源码.zip

    java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现...

    java nio 读文件

    java nio 读文件,java nio 读文件

    JAVA NIO 学习资料

    JAVA NIO学习资料JAVA NIO学习资料

    java nio入门学习,两个pdf

    java nio入门学习,两个pdfjava nio入门学习,两个pdf

    Java NIO测试示例

    Java NIO测试示例

    Java NIO实战开发多人聊天室

    01-Java NIO-课程简介.mp4 05-Java NIO-Channel-FileChannel详解(一).mp4 06-Java NIO-Channel-FileChannel详解(二).mp4 08-Java NIO-Channel-ServerSocketChannel.mp4 09-Java NIO-Channel-SocketChannel.mp4 ...

Global site tag (gtag.js) - Google Analytics