java.nio包是Java在1.4之后增加的,用来提高I/O操作的效率。在nio包中主要包括以下几个类或接口:

* Buffer:缓冲区,用来临时存放输入或输出数据。

* Charset:用来把Unicode字符编码和其它字符编码互转。

* Channel:数据传输通道,用来把Buffer中的数据写入到数据源,或者把数据源中的数据读入到Buffer。

* Selector:用来支持异步I/O操作,也叫非阻塞I/O操作。

nio包中主要通过下面两个方面来提高I/O操作效率:

* 通过Buffer和Channel来提高I/O操作的速度。

* 通过Selector来支持非阻塞I/O操作。

下面来看一下程序中是怎么通过这些类库实现Socket功能。

首先介绍一下几个辅助类

辅助类SerializableUtil,这个类用来把java对象序列化成字节数组,或者把字节数组反序列化成java对象。

  1. package com.googlecode.garbagecan.test.socket;
  2. import java.io.ByteArrayInputStream;
  3. import java.io.ByteArrayOutputStream;
  4. import java.io.IOException;
  5. import java.io.ObjectInputStream;
  6. import java.io.ObjectOutputStream;
  7. public class SerializableUtil {
  8. public static byte[] toBytes(Object object) {
  9. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  10. ObjectOutputStream oos = null;
  11. try {
  12. oos = new ObjectOutputStream(baos);
  13. oos.writeObject(object);
  14. byte[] bytes = baos.toByteArray();
  15. return bytes;
  16. } catch(IOException ex) {
  17. throw new RuntimeException(ex.getMessage(), ex);
  18. } finally {
  19. try {
  20. oos.close();
  21. } catch (Exception e) {}
  22. }
  23. }
  24. public static Object toObject(byte[] bytes) {
  25. ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
  26. ObjectInputStream ois = null;
  27. try {
  28. ois = new ObjectInputStream(bais);
  29. Object object = ois.readObject();
  30. return object;
  31. } catch(IOException ex) {
  32. throw new RuntimeException(ex.getMessage(), ex);
  33. } catch(ClassNotFoundException ex) {
  34. throw new RuntimeException(ex.getMessage(), ex);
  35. } finally {
  36. try {
  37. ois.close();
  38. } catch (Exception e) {}
  39. }
  40. }
  41. }

辅助类MyRequestObject和MyResponseObject,这两个类是普通的java对象,实现了Serializable接口。MyRequestObject类是Client发出的请求,MyResponseObject是Server端作出的响应。

  1. package com.googlecode.garbagecan.test.socket.nio;
  2. import java.io.Serializable;
  3. public class MyRequestObject implements Serializable {
  4. private static final long serialVersionUID = 1L;
  5. private String name;
  6. private String value;
  7. private byte[] bytes;
  8. public MyRequestObject(String name, String value) {
  9. this.name = name;
  10. this.value = value;
  11. this.bytes = new byte[1024];
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. public String getValue() {
  20. return value;
  21. }
  22. public void setValue(String value) {
  23. this.value = value;
  24. }
  25. @Override
  26. public String toString() {
  27. StringBuffer sb = new StringBuffer();
  28. sb.append("Request [name: " + name  + ", value: " + value + ", bytes: " + bytes.length+ "]");
  29. return sb.toString();
  30. }
  31. }
  32. package com.googlecode.garbagecan.test.socket.nio;
  33. import java.io.Serializable;
  34. public class MyResponseObject implements Serializable {
  35. private static final long serialVersionUID = 1L;
  36. private String name;
  37. private String value;
  38. private byte[] bytes;
  39. public MyResponseObject(String name, String value) {
  40. this.name = name;
  41. this.value = value;
  42. this.bytes = new byte[1024];
  43. }
  44. public String getName() {
  45. return name;
  46. }
  47. public void setName(String name) {
  48. this.name = name;
  49. }
  50. public String getValue() {
  51. return value;
  52. }
  53. public void setValue(String value) {
  54. this.value = value;
  55. }
  56. @Override
  57. public String toString() {
  58. StringBuffer sb = new StringBuffer();
  59. sb.append("Response [name: " + name  + ", value: " + value + ", bytes: " + bytes.length+ "]");
  60. return sb.toString();
  61. }
  62. }

下面主要看一下Server端的代码,其中有一些英文注释对理解代码很有帮助,注释主要是来源jdk的文档和例子,这里就没有再翻译

  1. package com.googlecode.garbagecan.test.socket.nio;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.IOException;
  4. import java.net.InetSocketAddress;
  5. import java.nio.ByteBuffer;
  6. import java.nio.channels.ClosedChannelException;
  7. import java.nio.channels.SelectionKey;
  8. import java.nio.channels.Selector;
  9. import java.nio.channels.ServerSocketChannel;
  10. import java.nio.channels.SocketChannel;
  11. import java.util.Iterator;
  12. import java.util.logging.Level;
  13. import java.util.logging.Logger;
  14. import com.googlecode.garbagecan.test.socket.SerializableUtil;
  15. public class MyServer3 {
  16. private final static Logger logger = Logger.getLogger(MyServer3.class.getName());
  17. public static void main(String[] args) {
  18. Selector selector = null;
  19. ServerSocketChannel serverSocketChannel = null;
  20. try {
  21. // Selector for incoming time requests
  22. selector = Selector.open();
  23. // Create a new server socket and set to non blocking mode
  24. serverSocketChannel = ServerSocketChannel.open();
  25. serverSocketChannel.configureBlocking(false);
  26. // Bind the server socket to the local host and port
  27. serverSocketChannel.socket().setReuseAddress(true);
  28. serverSocketChannel.socket().bind(new InetSocketAddress(10000));
  29. // Register accepts on the server socket with the selector. This
  30. // step tells the selector that the socket wants to be put on the
  31. // ready list when accept operations occur, so allowing multiplexed
  32. // non-blocking I/O to take place.
  33. serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
  34. // Here's where everything happens. The select method will
  35. // return when any operations registered above have occurred, the
  36. // thread has been interrupted, etc.
  37. while (selector.select() > 0) {
  38. // Someone is ready for I/O, get the ready keys
  39. Iterator<SelectionKey> it = selector.selectedKeys().iterator();
  40. // Walk through the ready keys collection and process date requests.
  41. while (it.hasNext()) {
  42. SelectionKey readyKey = it.next();
  43. it.remove();
  44. // The key indexes into the selector so you
  45. // can retrieve the socket that's ready for I/O
  46. execute((ServerSocketChannel) readyKey.channel());
  47. }
  48. }
  49. } catch (ClosedChannelException ex) {
  50. logger.log(Level.SEVERE, null, ex);
  51. } catch (IOException ex) {
  52. logger.log(Level.SEVERE, null, ex);
  53. } finally {
  54. try {
  55. selector.close();
  56. } catch(Exception ex) {}
  57. try {
  58. serverSocketChannel.close();
  59. } catch(Exception ex) {}
  60. }
  61. }
  62. private static void execute(ServerSocketChannel serverSocketChannel) throws IOException {
  63. SocketChannel socketChannel = null;
  64. try {
  65. socketChannel = serverSocketChannel.accept();
  66. MyRequestObject myRequestObject = receiveData(socketChannel);
  67. logger.log(Level.INFO, myRequestObject.toString());
  68. MyResponseObject myResponseObject = new MyResponseObject(
  69. "response for " + myRequestObject.getName(),
  70. "response for " + myRequestObject.getValue());
  71. sendData(socketChannel, myResponseObject);
  72. logger.log(Level.INFO, myResponseObject.toString());
  73. } finally {
  74. try {
  75. socketChannel.close();
  76. } catch(Exception ex) {}
  77. }
  78. }
  79. private static MyRequestObject receiveData(SocketChannel socketChannel) throws IOException {
  80. MyRequestObject myRequestObject = null;
  81. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  82. ByteBuffer buffer = ByteBuffer.allocate(1024);
  83. try {
  84. byte[] bytes;
  85. int size = 0;
  86. while ((size = socketChannel.read(buffer)) >= 0) {
  87. buffer.flip();
  88. bytes = new byte[size];
  89. buffer.get(bytes);
  90. baos.write(bytes);
  91. buffer.clear();
  92. }
  93. bytes = baos.toByteArray();
  94. Object obj = SerializableUtil.toObject(bytes);
  95. myRequestObject = (MyRequestObject)obj;
  96. } finally {
  97. try {
  98. baos.close();
  99. } catch(Exception ex) {}
  100. }
  101. return myRequestObject;
  102. }
  103. private static void sendData(SocketChannel socketChannel, MyResponseObject myResponseObject) throws IOException {
  104. byte[] bytes = SerializableUtil.toBytes(myResponseObject);
  105. ByteBuffer buffer = ByteBuffer.wrap(bytes);
  106. socketChannel.write(buffer);
  107. }
  108. }

下面是Client的代码,代码比较简单就是启动了100个线程来访问Server

  1. package com.googlecode.garbagecan.test.socket.nio;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.IOException;
  4. import java.net.InetSocketAddress;
  5. import java.net.SocketAddress;
  6. import java.nio.ByteBuffer;
  7. import java.nio.channels.SocketChannel;
  8. import java.util.logging.Level;
  9. import java.util.logging.Logger;
  10. import com.googlecode.garbagecan.test.socket.SerializableUtil;
  11. public class MyClient3 {
  12. private final static Logger logger = Logger.getLogger(MyClient3.class.getName());
  13. public static void main(String[] args) throws Exception {
  14. for (int i = 0; i < 100; i++) {
  15. final int idx = i;
  16. new Thread(new MyRunnable(idx)).start();
  17. }
  18. }
  19. private static final class MyRunnable implements Runnable {
  20. private final int idx;
  21. private MyRunnable(int idx) {
  22. this.idx = idx;
  23. }
  24. public void run() {
  25. SocketChannel socketChannel = null;
  26. try {
  27. socketChannel = SocketChannel.open();
  28. SocketAddress socketAddress = new InetSocketAddress("localhost", 10000);
  29. socketChannel.connect(socketAddress);
  30. MyRequestObject myRequestObject = new MyRequestObject("request_" + idx, "request_" + idx);
  31. logger.log(Level.INFO, myRequestObject.toString());
  32. sendData(socketChannel, myRequestObject);
  33. MyResponseObject myResponseObject = receiveData(socketChannel);
  34. logger.log(Level.INFO, myResponseObject.toString());
  35. } catch (Exception ex) {
  36. logger.log(Level.SEVERE, null, ex);
  37. } finally {
  38. try {
  39. socketChannel.close();
  40. } catch(Exception ex) {}
  41. }
  42. }
  43. private void sendData(SocketChannel socketChannel, MyRequestObject myRequestObject) throws IOException {
  44. byte[] bytes = SerializableUtil.toBytes(myRequestObject);
  45. ByteBuffer buffer = ByteBuffer.wrap(bytes);
  46. socketChannel.write(buffer);
  47. socketChannel.socket().shutdownOutput();
  48. }
  49. private MyResponseObject receiveData(SocketChannel socketChannel) throws IOException {
  50. MyResponseObject myResponseObject = null;
  51. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  52. try {
  53. ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
  54. byte[] bytes;
  55. int count = 0;
  56. while ((count = socketChannel.read(buffer)) >= 0) {
  57. buffer.flip();
  58. bytes = new byte[count];
  59. buffer.get(bytes);
  60. baos.write(bytes);
  61. buffer.clear();
  62. }
  63. bytes = baos.toByteArray();
  64. Object obj = SerializableUtil.toObject(bytes);
  65. myResponseObject = (MyResponseObject) obj;
  66. socketChannel.socket().shutdownInput();
  67. } finally {
  68. try {
  69. baos.close();
  70. } catch(Exception ex) {}
  71. }
  72. return myResponseObject;
  73. }
  74. }
  75. }

最后测试上面的代码,首先运行Server类,然后运行Client类,就可以分别在Server端和Client端控制台看到发送或接收到的MyRequestObject或MyResponseObject对象了。

转:Java NIO(2)的更多相关文章

  1. 源码分析netty服务器创建过程vs java nio服务器创建

    1.Java NIO服务端创建 首先,我们通过一个时序图来看下如何创建一个NIO服务端并启动监听,接收多个客户端的连接,进行消息的异步读写. 示例代码(参考文献[2]): import java.io ...

  2. 支撑Java NIO 与 NodeJS的底层技术

    支撑Java NIO 与 NodeJS的底层技术 众所周知在近几个版本的Java中增加了一些对Java NIO.NIO2的支持,与此同时NodeJS技术栈中最为人称道的优势之一就是其高性能IO,那么我 ...

  3. JAVA NIO学习笔记1 - 架构简介

    最近项目中遇到不少NIO相关知识,之前对这块接触得较少,算是我的一个盲区,打算花点时间学习,简单做一点个人学习总结. 简介 NIO(New IO)是JDK1.4以后推出的全新IO API,相比传统IO ...

  4. Java NIO概述

    Java NIO 由以下几个核心部分组成: Channels Buffers Selectors 虽然 Java NIO 中除此之外还有很多类和组件,但在我看来,Channel,Buffer 和 Se ...

  5. JAVA NIO Socket通道

      DatagramChannel和SocketChannel都实现定义读写功能,ServerSocketChannel不实现,只负责监听传入的连接,并建立新的SocketChannel,本身不传输数 ...

  6. JAVA NIO FileChannel 内存映射文件

      文件通道总是阻塞式的. 文件通道不能创建,只能通过(RandomAccessFile.FileInputStream.FileOutputStream)getChannel()获得,具有与File ...

  7. java nio系列文章

    java nio系列教程 基于NIO的Client/Server程序实践 (推荐) java nio与并发编程相关电子书籍   (访问密码 48dd) 理解NIO nio学习记录 图解ByteBuff ...

  8. Java NIO (转)

    Java NIO提供了与标准IO不同的IO工作方式: Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(B ...

  9. Java NIO使用及原理分析(1-4)(转)

    转载的原文章也找不到!从以下博客中找到http://blog.csdn.net/wuxianglong/article/details/6604817 转载自:李会军•宁静致远 最近由于工作关系要做一 ...

  10. Java - NIO

    java.nio:NIO-2: NIO 面向流的IO体系一次只能处理一个或多个字节/字符,直至读取所有字节/符,且流中的数据不能前后移动.效率低,当数据源中没有数据时会阻塞线程.Java-4提供的新A ...

随机推荐

  1. javascript遍历方法总结

    forEach 循环 JavaScript诞生已经有20多年了,我们一直使用的用来循环一个数组的方法是这样的: for (var index = 0; index < myArray.lengt ...

  2. python之获取微信好友列表并保存文档中

    代码如下 from wxpy import * from pprint import pprint #登录微信 bot = Bot() my_friend = bot.friends() f = op ...

  3. [Codeforces958F2]Lightsabers (medium)(思维)

    Description 题目链接 Solution 设一个l指针指向当前数列左边,从左往右扫描一遍,将当前颜色记录, 当所有颜色都得到后,进行判断,如果当前l指向的颜色大于需要的颜色,l后移一位,然后 ...

  4. Spring---bean的命名

    每个Bean可以有一个或多个 id,我们把第一个 id 称为“标识符”,其余id叫做“别名”,这些id在 IoC 容器中必须唯一. Bean  id 的命名约定: 遵循XML命名规范 由字母,数字,下 ...

  5. 7.Mongodb安全性流程

    1.安全性流程 2.超级管理员 为了更安全的访问mongodb,需要访问者提供用户名和密码,于是需要在mongodb中创建用户 采用了角色-用户-数据库的安全管理方式 常用系统角色如下: root:只 ...

  6. 03019_过滤器Filter

    1.Filter的简介 (1)Filter是对客户端访问资源的过滤,符合条件放行,不符合条件不放行,并且可以对目标资源访问前后进行逻辑处理: (2)快速入门步骤 ①编写一个过滤器的类实现Filter接 ...

  7. CentOS 7.X 搭建时间服务器 --- chrony

    之前centos6我们一直用的ntp时间服务器,虽然到CentOS7上也可以装ntp.但是各种坑啊.这次换一个时间同步工具---->chrony ======================== ...

  8. DbVisualizer 解决中文乱码问题

    在SQL Commander中,sql语句中如果有中文,显示是‘口口口’. 解决办法如下: 在Tools->tool Properties->General->Appearance- ...

  9. 剑指Offer - 九度1515 - 打印1到最大的N位数

    剑指Offer - 九度1515 - 打印1到最大的N位数2013-11-30 01:11 题目描述: 给定一个数字N,打印从1到最大的N位数. 输入: 每个输入文件仅包含一组测试样例.对于每个测试案 ...

  10. Scrapy使用示例

    很多网站都提供了浏览者本地的天气信息,这些信息是如何获取到的呢,方法有很多种,大多是利用某些网站提供的天气api获取的,也有利用爬虫采集的.本文就介绍如何用Scrapy来采集天气信息(从新浪天气频道采 ...