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. Servlet异步处理和文件上传

    1. 什么是异步处理     原来,在服务器没有结束响应之前,浏览器是看不到响应内容的!只有响应结束时,浏览器才能显示结果!     现在异步处理的作用:在服务器开始响应后,浏览器就可以看到响应内容, ...

  2. iOS-重构微博cell模型

    一.Frame模型: -------------------WeiboFrame.h-------------------------------------------------- ------- ...

  3. ASCII码排序 南阳acm4

    ASCII码排序 时间限制:3000 ms  |  内存限制:65535 KB 难度:2   描述 输入三个字符(可以重复)后,按各字符的ASCII码从小到大的顺序输出这三个字符.   输入 第一行输 ...

  4. 用go run命令启动main package中的多个文件

    linux: go run *.go windows: go build后运行main.exe

  5. 【UE4】二十三、UE4笔试面试题

    在CSDN博客看到的,带着这些问题,多多留意,正所谓带着问题学习. 一. 1.Actor的EndPlay事件在哪些时候会调用? 2.BlueprintImplementableEvent和Bluepr ...

  6. sparkStreaming统计各平台最近一分钟实时注册收入 时间段,平台,金额,订单数

    样例数据: __clientip=10.10.9.153&paymentstatus=0&__opip=&memberid=89385239&iamount=1& ...

  7. Android Config通用类来记录信息

    1.整体分析 1.1.源代码,可以直接Copy. public class Config { private static int M = 1024 * 1024; private volatile ...

  8. mysql安装与基本管理,mysql密码破解

    一.MySQL介绍 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下公司.MySQL 最流行的关系型数据库管理系统,在 WEB 应用方面MySQL是 ...

  9. laravel5.5任务调度

    目录 1. 定义调度 1.1 使用Closure 1.2 Artisan 命令调度 1.3 队列任务调度 1.4 Shell 命令调度 1.5 调度频率设置 1.6 闭包测试限制 1.7 避免任务重复 ...

  10. python实现单链表的反转

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #!/usr/bin/env python #coding = utf-8 ...