六狼论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博账号登陆

只需一步,快速开始

搜索
查看: 28|回复: 0

Java NIO类库Selector机制解析(上)

[复制链接]

升级  56.05%

691

主题

691

主题

691

主题

探花

Rank: 6Rank: 6

积分
2121
 楼主| 发表于 2013-1-26 13:55:43 | 显示全部楼层 |阅读模式
Java NIO类库Selector机制解析(上)



赵锟   陈皓




一、 前言



自从J2SE 1.4版本以来,JDK发布了全新的I/O类库,简称NIO,其不但引入了全新的高效的I/O机制,同时,也引入了多路复用的异步模式。NIO的包中主要包含了这样几种抽象数据类型:



  • Buffer:包含数据且用于读写的线形表结构。其中还提供了一个特殊类用于内存映射文件的I/O操作。   
  • Charset:它提供Unicode字符串影射到字节序列以及逆映射的操作。   
  • Channels:包含socket,file和pipe三种管道,都是全双工的通道。   
  • Selector:多个异步I/O操作集中到一个或多个线程中(可以被看成是Unix中select()函数的面向对象版本)。


我的大学同学赵锟在使用NIO类库书写相关网络程序的时候,发现了一些Java异常RuntimeException,异常的报错信息让他开始了对NIO的Selector进行了一些调查。当赵锟对我共享了Selector的一些底层机制的猜想和调查时候,我们觉得这是一件很有意思的事情,于是在伙同赵锟进行过一系列的调查后,我俩发现了很多有趣的事情,于是导致了这篇文章的产生。这也是为什么本文的作者署名为我们两人的原因。


先要说明的一点是,赵锟和我本质上都是出身于Unix/Linux/C/C++的开发人员,对于Java,这并不是我们的长处,这篇文章本质上出于对Java的Selector的好奇,因为从表面上来看Selector似乎做到了一些让我们这些C/C++出身的人比较惊奇的事情。


下面让我来为你讲述一下这段故事。


二、 故事开始 : 让C++程序员写Java程序!



没有严重内存问题,大量丰富的SDK类库,超容易的跨平台,除了在性能上有些微辞,C++出身的程序员从来都不会觉得Java是一件很困难的事情。当然,对于长期习惯于使用操作系统API(系统调用System Call)的C/C++程序来说,面对Java中的比较“另类”地操作系统资源的方法可能会略感困惑,但万变不离其宗,只需要对面向对象的设计模式有一定的了解,用不了多长时间,Java的SDK类库也能玩得随心所欲。


在使用Java进行相关网络程序的的设计时,出身C/C++的人,首先想到的框架就是多路复用,想到多路复用,Unix/Linux下马上就能让从想到select, poll, epoll系统调用。于是,在看到Java的NIO中的Selector类时必然会倍感亲切。稍加查阅一下SDK手册以及相关例程,不一会儿,一个多路复用的框架便呈现出来,随手做个单元测试,没啥问题,一切和C/C++照旧。然后告诉兄弟们,框架搞定,以后咱们就在Windows上开发及单元测试,完成后到运行环境Unix上集成测试。心中并暗自念到,跨平台就好啊,开发活动都可以跨平台了。


然而,好景不长,随着代码越来越多,逻辑越来越复杂。好好的框架居然在Windows上单元测试运行开始出现异常,看着Java运行异常出错的函数栈,异常居然由Selector.open()抛出,错误信息居然是Unable to establish loopback connection。


“Selector.open()居然报loopback connection错误,凭什么?不应该啊?open的时候又没有什么loopbacksocket连接,怎么会报这个错?



长期使用C/C++的程序当然会对操作系统的调用非常熟悉,虽然Java的虚拟机搞的什么系统调用都不见了,但C/C++的程序员必然要比Java程序敏感许多。


三、 开始调查 : 怎么Java这么“傻”!



于是,C/C++的老鸟从SystemInternals上下载Process Explorer来查看一下究竟是什么个Loopback Connection。 果然,打开java运行进程,发现有一些自己连接自己的localhost的TCP/IP链接。于是另一个问题又出现了,


凭什么啊?为什么会有自己和自己的连接?我程序里没有自己连接自己啊,怎么可能会有这样的链接啊?而自己连接自己的端口号居然是些奇怪的端口。


问题变得越来越蹊跷了。难道这都是Selector.open()在做怪?难道Selector.open()要创建一个自己连接自己的链接?写个程序看看:


<div style="padding-right: 4pt; padding-left: 4pt; background: #cccccc; padding-bottom: 1pt; padding-top: 1pt;">import java.nio.channels.Selector;

import java.lang.RuntimeException;

import java.lang.Thread;

public class TestSelector {

private static final int MAXSIZE=5;

public static final void main( String argc[] ) {

Selector [] sels = new Selector[ MAXSIZE];



try{

for( int i = 0 ;i< MAXSIZE ;++i ) {

sels = Selector.open();

//sels.close();

}

Thread.sleep(30000);

}catch( Exception ex ){

throw new RuntimeException( ex );

}

}

}
您需要登录后才可以回帖 登录 | 立即注册 新浪微博账号登陆

本版积分规则

快速回复 返回顶部 返回列表