Chinaunix首页 | 论坛 | 博客
  • 博客访问: 579997
  • 博文数量: 718
  • 博客积分: 4000
  • 博客等级: 上校
  • 技术积分: 4960
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-17 13:24
文章分类

全部博文(718)

文章存档

2011年(1)

2008年(717)

我的朋友

分类:

2008-10-17 13:33:38


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

--------------------next---------------------

阅读(265) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~