服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

javai/oapi之性能分析(下)


  四、注册与处理过程详解
  接下来我们要分析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();
  }

扫描关注微信公众号