网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > Java
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
网络编程:ASP教程,ASP.NET教程,PHP教程,JSP教程,C#教程,数据库,XML教程,Ajax,Java,Perl,Shell,VB教程,Delphi,C/C++教程,软件工程,J2EE/J2ME,移动开发
本月文章推荐
.Java的double类型探索..
.AOP在大规模软件开发项目中应用的.
.Java线程的深入探讨.
.Java 字符编码问题.
.让数据更安全保护SQLServer的十个.
.使用Google的Web Service.
.使用JWSDP完成Web Service在java.
.向高手请教ant构建工具的类装载器.
.利用JBuilder开发调试Servlet.
.关于applet写入文件的处理.
.EJB查询语言.
.J2ME编程最佳实践之灵活的RMS应用.
.如何实现Applet之间跨浏览器窗口.
.EJB系列教程之三.
.Struts开发技巧.
.Web Service 和 J2EE.
.ScriptEngine 函数.
.java基础知识——java入门与加深.
.j2ee 笔记 --基础.
.精通语言不等于是一个好的软件开.

Java I/O API之性能分析 (下)

发表日期:2008-1-5


  上一篇:Java I/O API之性能分析 (上)

  四、注册与处理过程详解

  接下来我们要分析Connection的register()方法。前面我们总是说用Selector注册的连接,其实这是一种简化的说法。实际上,用Selector注册的是一个java.nio.channels.SocketChannel对象,但只针对特定的I/O操作。注册之后,有一个java.nio.channels.SelectionKey被返回。这个选择键可以通过attach()方法关联到任意对象。为了通过键获得连接,这里把Connection对象关联到键。这样,我们就可以从Selector间接地获得一个Connection。


  public void register(Selector selector)
  throws IOException {
  key = socketChannel.register(selector, SelectionKey.OP_READ);
  key.attach(this);
  }

  回过头来看ConnectionSelector。select()方法的返回值表示有多少连接已经做好了I/O操作的预备。假如返回值是0,则返回;否则,调用selectedKeys()获得键的集合(Set),从这些键获得以前关联的Connection对象,然后调用其readRequest()或writeResponse()方法,具体调用哪一个方法由连接被注册为读取操作还是写入操作决定。

  现在再来看Connection类。Connection类代表着连接,处理所有协议有关的细节。在构造函数中,通过参数传入的SocketChannel被设置成非阻塞模式,这对于服务器来说是很重要的。另外,构造函数还设置了一些默认值,分配了缓冲区requestLineBuffer。由于分配直接缓冲区代价稍高,且这里的每一个连接都用一个新的缓冲区,因此这里使用java.nio.ByteBuffer.allocate()而不是ByteBuffer.allocateDirect()。假如重用缓冲区,直接缓冲区可能具有更高的效率。


  public Connection(SocketChannel socketChannel)
  throws IOException {
  this.socketChannel = socketChannel;
  ...
  socketChannel.configureBlocking(false);
  requestLineBuffer = ByteBuffer.allocate(512);
  ...
  }

  完成所有初始化工作且SocketChannel做好了读取预备之后,ConnectionSelector调用了readRequest()方法,利用socketChannel.read(requestLineBuffer)方法把所有可用的数据读入缓冲区。假如不能读取完整的行,则返回发出调用的ConnectionSelector,答应另一个连接进入处理过程;反之,假如成功地读取了整个行,接下来应该做的是象在Httpd中一样解析请求。假如当前的请求合法,程序为请求目标文件创建一个java.nio.Channels.FileChannel,并调用prepareForResponse()方法。


  private void prepareForResponse() throws IOException {
  StringBuffer responseLine = new StringBuffer(128);
  ...
  responseLineBuffer = ByteBuffer.wrap(
  responseLine.toString().getBytes("ASCII")
  );
  key.interestOps(SelectionKey.OP_WRITE);
  key.selector().wakeup();
  }

  prepareForResponse()方法构造出缓冲区responseLine以及(假如必要的话)应答头或错误信息,并把这些数据写入responseLineBuffer。这个ByteBuffer是一个byte数组的简单的封装器。

生成待输出的数据之后,我们还要通知ConnectionSelector:从现在开始不再读取数据,而是要写入数据了。这个通知通过调用选择键的interestedOps(SelectionKey.OP_WRITE)方法完成。为了保证选择器能够迅速熟悉到连接操作状态的变化,接着还要调用wakeup()方法。接下来ConnectionSelector调用连接的writeResponse()方法。首先,responseLineBuffer被写入到Socket管道。假如缓冲区的内容全部被写入,而且还有被请求的文件需要发送,接着调用前面打开的FileChannel的transferTo()方法。transferTo()方法通常能够高效地把数据从文件传输到管道,但实际的传输效率依靠于底层的操作系统。任何时候,被传输的数据量至多相当于在无阻塞的情况下可写入目标管道的数据量。为安全和确保各个连接之间的公平起见,这里把上限设置成64 KB。

  假如所有数据都已经传输完毕,close()执行清理工作。取消Connection的注册是这里的主要任务,具体通过调用键的cancel()方法完成。



上一篇:函数式组合子逻辑Java parser框架(一) 人气:913
下一篇:深入浅出Java的访问者模式 人气:596
浏览全部Java的内容 Dreamweaver插件下载 网页广告代码 祝你圣诞节快乐 2009年新年快乐