转:Java NIO(2)
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对象。
- package com.googlecode.garbagecan.test.socket;
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.io.ObjectInputStream;
- import java.io.ObjectOutputStream;
- public class SerializableUtil {
- public static byte[] toBytes(Object object) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ObjectOutputStream oos = null;
- try {
- oos = new ObjectOutputStream(baos);
- oos.writeObject(object);
- byte[] bytes = baos.toByteArray();
- return bytes;
- } catch(IOException ex) {
- throw new RuntimeException(ex.getMessage(), ex);
- } finally {
- try {
- oos.close();
- } catch (Exception e) {}
- }
- }
- public static Object toObject(byte[] bytes) {
- ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
- ObjectInputStream ois = null;
- try {
- ois = new ObjectInputStream(bais);
- Object object = ois.readObject();
- return object;
- } catch(IOException ex) {
- throw new RuntimeException(ex.getMessage(), ex);
- } catch(ClassNotFoundException ex) {
- throw new RuntimeException(ex.getMessage(), ex);
- } finally {
- try {
- ois.close();
- } catch (Exception e) {}
- }
- }
- }
辅助类MyRequestObject和MyResponseObject,这两个类是普通的java对象,实现了Serializable接口。MyRequestObject类是Client发出的请求,MyResponseObject是Server端作出的响应。
- package com.googlecode.garbagecan.test.socket.nio;
- import java.io.Serializable;
- public class MyRequestObject implements Serializable {
- private static final long serialVersionUID = 1L;
- private String name;
- private String value;
- private byte[] bytes;
- public MyRequestObject(String name, String value) {
- this.name = name;
- this.value = value;
- this.bytes = new byte[1024];
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getValue() {
- return value;
- }
- public void setValue(String value) {
- this.value = value;
- }
- @Override
- public String toString() {
- StringBuffer sb = new StringBuffer();
- sb.append("Request [name: " + name + ", value: " + value + ", bytes: " + bytes.length+ "]");
- return sb.toString();
- }
- }
- package com.googlecode.garbagecan.test.socket.nio;
- import java.io.Serializable;
- public class MyResponseObject implements Serializable {
- private static final long serialVersionUID = 1L;
- private String name;
- private String value;
- private byte[] bytes;
- public MyResponseObject(String name, String value) {
- this.name = name;
- this.value = value;
- this.bytes = new byte[1024];
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getValue() {
- return value;
- }
- public void setValue(String value) {
- this.value = value;
- }
- @Override
- public String toString() {
- StringBuffer sb = new StringBuffer();
- sb.append("Response [name: " + name + ", value: " + value + ", bytes: " + bytes.length+ "]");
- return sb.toString();
- }
- }
下面主要看一下Server端的代码,其中有一些英文注释对理解代码很有帮助,注释主要是来源jdk的文档和例子,这里就没有再翻译
- package com.googlecode.garbagecan.test.socket.nio;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.net.InetSocketAddress;
- import java.nio.ByteBuffer;
- 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.util.Iterator;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- import com.googlecode.garbagecan.test.socket.SerializableUtil;
- public class MyServer3 {
- private final static Logger logger = Logger.getLogger(MyServer3.class.getName());
- public static void main(String[] args) {
- Selector selector = null;
- ServerSocketChannel serverSocketChannel = null;
- try {
- // Selector for incoming time requests
- selector = Selector.open();
- // Create a new server socket and set to non blocking mode
- serverSocketChannel = ServerSocketChannel.open();
- serverSocketChannel.configureBlocking(false);
- // Bind the server socket to the local host and port
- serverSocketChannel.socket().setReuseAddress(true);
- serverSocketChannel.socket().bind(new InetSocketAddress(10000));
- // Register accepts on the server socket with the selector. This
- // step tells the selector that the socket wants to be put on the
- // ready list when accept operations occur, so allowing multiplexed
- // non-blocking I/O to take place.
- serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
- // Here's where everything happens. The select method will
- // return when any operations registered above have occurred, the
- // thread has been interrupted, etc.
- while (selector.select() > 0) {
- // Someone is ready for I/O, get the ready keys
- Iterator<SelectionKey> it = selector.selectedKeys().iterator();
- // Walk through the ready keys collection and process date requests.
- while (it.hasNext()) {
- SelectionKey readyKey = it.next();
- it.remove();
- // The key indexes into the selector so you
- // can retrieve the socket that's ready for I/O
- execute((ServerSocketChannel) readyKey.channel());
- }
- }
- } catch (ClosedChannelException ex) {
- logger.log(Level.SEVERE, null, ex);
- } catch (IOException ex) {
- logger.log(Level.SEVERE, null, ex);
- } finally {
- try {
- selector.close();
- } catch(Exception ex) {}
- try {
- serverSocketChannel.close();
- } catch(Exception ex) {}
- }
- }
- private static void execute(ServerSocketChannel serverSocketChannel) throws IOException {
- SocketChannel socketChannel = null;
- try {
- socketChannel = serverSocketChannel.accept();
- MyRequestObject myRequestObject = receiveData(socketChannel);
- logger.log(Level.INFO, myRequestObject.toString());
- MyResponseObject myResponseObject = new MyResponseObject(
- "response for " + myRequestObject.getName(),
- "response for " + myRequestObject.getValue());
- sendData(socketChannel, myResponseObject);
- logger.log(Level.INFO, myResponseObject.toString());
- } finally {
- try {
- socketChannel.close();
- } catch(Exception ex) {}
- }
- }
- private static MyRequestObject receiveData(SocketChannel socketChannel) throws IOException {
- MyRequestObject myRequestObject = null;
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ByteBuffer buffer = ByteBuffer.allocate(1024);
- try {
- byte[] bytes;
- int size = 0;
- while ((size = socketChannel.read(buffer)) >= 0) {
- buffer.flip();
- bytes = new byte[size];
- buffer.get(bytes);
- baos.write(bytes);
- buffer.clear();
- }
- bytes = baos.toByteArray();
- Object obj = SerializableUtil.toObject(bytes);
- myRequestObject = (MyRequestObject)obj;
- } finally {
- try {
- baos.close();
- } catch(Exception ex) {}
- }
- return myRequestObject;
- }
- private static void sendData(SocketChannel socketChannel, MyResponseObject myResponseObject) throws IOException {
- byte[] bytes = SerializableUtil.toBytes(myResponseObject);
- ByteBuffer buffer = ByteBuffer.wrap(bytes);
- socketChannel.write(buffer);
- }
- }
下面是Client的代码,代码比较简单就是启动了100个线程来访问Server
- package com.googlecode.garbagecan.test.socket.nio;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.net.InetSocketAddress;
- import java.net.SocketAddress;
- import java.nio.ByteBuffer;
- import java.nio.channels.SocketChannel;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- import com.googlecode.garbagecan.test.socket.SerializableUtil;
- public class MyClient3 {
- private final static Logger logger = Logger.getLogger(MyClient3.class.getName());
- public static void main(String[] args) throws Exception {
- for (int i = 0; i < 100; i++) {
- final int idx = i;
- new Thread(new MyRunnable(idx)).start();
- }
- }
- private static final class MyRunnable implements Runnable {
- private final int idx;
- private MyRunnable(int idx) {
- this.idx = idx;
- }
- public void run() {
- SocketChannel socketChannel = null;
- try {
- socketChannel = SocketChannel.open();
- SocketAddress socketAddress = new InetSocketAddress("localhost", 10000);
- socketChannel.connect(socketAddress);
- MyRequestObject myRequestObject = new MyRequestObject("request_" + idx, "request_" + idx);
- logger.log(Level.INFO, myRequestObject.toString());
- sendData(socketChannel, myRequestObject);
- MyResponseObject myResponseObject = receiveData(socketChannel);
- logger.log(Level.INFO, myResponseObject.toString());
- } catch (Exception ex) {
- logger.log(Level.SEVERE, null, ex);
- } finally {
- try {
- socketChannel.close();
- } catch(Exception ex) {}
- }
- }
- private void sendData(SocketChannel socketChannel, MyRequestObject myRequestObject) throws IOException {
- byte[] bytes = SerializableUtil.toBytes(myRequestObject);
- ByteBuffer buffer = ByteBuffer.wrap(bytes);
- socketChannel.write(buffer);
- socketChannel.socket().shutdownOutput();
- }
- private MyResponseObject receiveData(SocketChannel socketChannel) throws IOException {
- MyResponseObject myResponseObject = null;
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
- byte[] bytes;
- int count = 0;
- while ((count = socketChannel.read(buffer)) >= 0) {
- buffer.flip();
- bytes = new byte[count];
- buffer.get(bytes);
- baos.write(bytes);
- buffer.clear();
- }
- bytes = baos.toByteArray();
- Object obj = SerializableUtil.toObject(bytes);
- myResponseObject = (MyResponseObject) obj;
- socketChannel.socket().shutdownInput();
- } finally {
- try {
- baos.close();
- } catch(Exception ex) {}
- }
- return myResponseObject;
- }
- }
- }
最后测试上面的代码,首先运行Server类,然后运行Client类,就可以分别在Server端和Client端控制台看到发送或接收到的MyRequestObject或MyResponseObject对象了。
转:Java NIO(2)的更多相关文章
- 源码分析netty服务器创建过程vs java nio服务器创建
1.Java NIO服务端创建 首先,我们通过一个时序图来看下如何创建一个NIO服务端并启动监听,接收多个客户端的连接,进行消息的异步读写. 示例代码(参考文献[2]): import java.io ...
- 支撑Java NIO 与 NodeJS的底层技术
支撑Java NIO 与 NodeJS的底层技术 众所周知在近几个版本的Java中增加了一些对Java NIO.NIO2的支持,与此同时NodeJS技术栈中最为人称道的优势之一就是其高性能IO,那么我 ...
- JAVA NIO学习笔记1 - 架构简介
最近项目中遇到不少NIO相关知识,之前对这块接触得较少,算是我的一个盲区,打算花点时间学习,简单做一点个人学习总结. 简介 NIO(New IO)是JDK1.4以后推出的全新IO API,相比传统IO ...
- Java NIO概述
Java NIO 由以下几个核心部分组成: Channels Buffers Selectors 虽然 Java NIO 中除此之外还有很多类和组件,但在我看来,Channel,Buffer 和 Se ...
- JAVA NIO Socket通道
DatagramChannel和SocketChannel都实现定义读写功能,ServerSocketChannel不实现,只负责监听传入的连接,并建立新的SocketChannel,本身不传输数 ...
- JAVA NIO FileChannel 内存映射文件
文件通道总是阻塞式的. 文件通道不能创建,只能通过(RandomAccessFile.FileInputStream.FileOutputStream)getChannel()获得,具有与File ...
- java nio系列文章
java nio系列教程 基于NIO的Client/Server程序实践 (推荐) java nio与并发编程相关电子书籍 (访问密码 48dd) 理解NIO nio学习记录 图解ByteBuff ...
- Java NIO (转)
Java NIO提供了与标准IO不同的IO工作方式: Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(B ...
- Java NIO使用及原理分析(1-4)(转)
转载的原文章也找不到!从以下博客中找到http://blog.csdn.net/wuxianglong/article/details/6604817 转载自:李会军•宁静致远 最近由于工作关系要做一 ...
- Java - NIO
java.nio:NIO-2: NIO 面向流的IO体系一次只能处理一个或多个字节/字符,直至读取所有字节/符,且流中的数据不能前后移动.效率低,当数据源中没有数据时会阻塞线程.Java-4提供的新A ...
随机推荐
- 前端性能优化JavaScript篇
关于前端性能优化的讨论一直都很多,包罗的知识也很多,可以说性能优化只有更好,没有最好.前面我写了一篇关于css优化的总结文章,今天再从javascript方面聊一聊. 1.从资源加载方面来说,浏览器的 ...
- Ado访问sqlserver 端口号非1433时 连接串的写法
Provider=SQLOLEDB.;Persist Security Info=False;Data Source=hostName,Port //注意用 逗号分隔主机名与端口号
- Python入门必学:数据类型和变量的用法
什么是数据类型?计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值.但是,计算机能处理的远不止数值,还可以处理文本.图形.音频.视频.网页等各种各样的数据,不同的数据, ...
- 线程、进程、协程和GIL(一)
参考链接:https://www.cnblogs.com/alex3714/articles/5230609.html https://www.cnblogs.com/work115/p/562027 ...
- vim+软件安装——06
vim在命令模式下的操作: 1.上下左右键可以自由走动 2.l 键 光标向右移动一个位置 3.h键 光标向左移动一个位置 4.j键 光标向下移动一行 5.k键 光标向上移动一行 6.^键 光标移动到当 ...
- 笔记-unittest实战
笔记-unittest实战 1. 框架图 2. 用例 编写自己的测试用例类,继承于基类 class ApiTestCase(unittest.TestCase): setUp方法会 ...
- 笔记-爬虫-selenium常用方法
笔记-爬虫-selenium常用方法 1. 查找元素 常用的查找方法 find_element_by_name find_element_by_xpath find_element_by_l ...
- 【Java集合源码剖析】Java集合框架
Java集合工具包位于Java.util包下,包含了很多常用的数据结构,如数组.链表.栈.队列.集合.哈希表等.学习Java集合框架下大致可以分为如下五个部分:List列表.Set集合.Map映射.迭 ...
- 使用Oracle绿色客户端(InstantClient)连接远程Oracle的配置方法
非常简单的配置,网上一搜,有很多,但是还是想记录下来,说不定以后需要了,直接进自己的博客看看也好啊. 下载了PLSQL Developer 11,安装好了发现不能连接远程数据库,但是又不想安装orac ...
- 三层还是DDD,ORM还是Ado.Net,何去何从?
我本想把这个问题放到博问去,前几次有去博问问过之类的问题,无奈大神们可能都不屑回答别人的低级问题.所以放到随笔里,一方面把自己对ORM.架构的一些看法写下来抛砖引玉,另一方面最主要的是想寻求大神们指指 ...