Jetty的SelectChannelConnector分析

来源:互联网 发布:sql server 2014版本 编辑:程序博客网 时间:2024/05/06 17:13

Jetty的SelectChannelConnector分析

分类: 网络编程 503人阅读 评论(0) 收藏 举报

以前的一篇文章曾经分析过jetty的socketConnector,其实它的实现相对来说是比较简单的了,但是由于它是阻塞的io,所以在性能上并不好。。一般情况下都推荐使用SelectChannelConnector来替换掉。。。也就是所谓的NioConnector

SelectChannelConnector的实现就要复杂的多了。。而且因为将底层的io揉在了一起。。。。所以感觉这一块的代码不是很干净。。。又在想自己是否可以将底层的I/O全部替换掉,换成netty的实现。。。。。


好了。。先来看看SelectChannelConnector的类图吧:



在这里将比较重要的关联关系也展现了出来。。。

SelectorManager,从名字就可以看出它用来管理selector,它内部可能会有多个SelectSet,其实一般情况下都只有一个,SelectSet里面则是真正的管理selector的运行,以及注册事件的维护。。。


首先我们来看看SelectChannelConnector的一些重要属性吧:

[java] view plaincopy
  1. private transient ServerSocketChannel _acceptChannel;  //服务器监听channel  
  2. private long _lowResourcesConnections;  
  3. private long _lowResourcesMaxIdleTime;     
  4.   
  5. private SelectorManager _manager = new SelectorManager()  //创建selectManager对象  
  6. {  
  7.     protected SocketChannel acceptChannel(SelectionKey key) throws IOException  
  8.     {  
  9.         // TODO handle max connections  
  10.         SocketChannel channel = ((ServerSocketChannel)key.channel()).accept();  //用于后去连接的channel  
  11.         if (channel==null)  
  12.             return null;  
  13.         channel.configureBlocking(false);  //将接收到的socketChannel设置为非阻塞的  
  14.         Socket socket = channel.socket();  
  15.         configure(socket);  
  16.         return channel;  
  17.     }  
  18.   
  19.     public boolean dispatch(Runnable task) throws IOException  
  20.     {  
  21.         return getThreadPool().dispatch(task);  //将这个task放到线程池里面去运行  
  22.     }  
  23.   
  24.     protected void endPointClosed(SelectChannelEndPoint endpoint)  
  25.     {  
  26.         // TODO handle max connections and low resources  
  27.         connectionClosed((HttpConnection)endpoint.getConnection());  
  28.     }  
  29.   
  30.     protected void endPointOpened(SelectChannelEndPoint endpoint)  
  31.     {  
  32.         // TODO handle max connections and low resources  
  33.         connectionOpened((HttpConnection)endpoint.getConnection());  
  34.     }  
  35.   
  36.     //用于创建httpconnection  
  37.     protected Connection newConnection(SocketChannel channel,SelectChannelEndPoint endpoint)  
  38.     {  
  39.         return SelectChannelConnector.this.newConnection(channel,endpoint);  
  40.     }  
  41.     //用于创建ConnectorEndPoint  
  42.     protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey sKey) throws IOException  
  43.     {  
  44.         return SelectChannelConnector.this.newEndPoint(channel,selectSet,sKey);  
  45.     }  
  46. };  

首先最重要的当然是server端的监听器了。。。其次就是定义了SelectorManager,因为是一个抽象类,所以还具体的实现了一些他的方法,例如如何接收远程连接,如何dispatch任务等等。。。

我们知道,在server启动的时候,会启动内部的connector,那么我们这里来看看这个connector的启动过程吧:

[java] view plaincopy
  1. //connector的启动过程  
  2. protected void doStart() throws Exception {  
  3.     _manager.setSelectSets(getAcceptors());   //设置selectSet的数量,也就是每一个监听器都一个selector  
  4.     _manager.setMaxIdleTime(getMaxIdleTime());  //设置最大空闲时间  
  5.     _manager.setLowResourcesConnections(getLowResourcesConnections());  
  6.     _manager.setLowResourcesMaxIdleTime(getLowResourcesMaxIdleTime());  
  7.     _manager.start();   //启动manager  
  8.     open();   //这里会建立serversocketchannel  
  9.     _manager.register(_acceptChannel);  //将serversocketrChannler注册到selector上面去,其实是放在这个select的change数组上面,在select真正开始之前它会被注册到selector上面去  
  10.     super.doStart();  
  11. }  

首先是设置selectmanager的selectset的数量,因为只有一个监听,所以值也就是1了。。。

然后设置连接的最大空闲时间。。。低水平的链接数量啥的,然后就是selectormanager的启动,

open是打开当前的监听器。。然后将这个监听器注册到selectorManager上,。。。最后才是父类的dostart

那么我们在这里先来看看selectmanager的启动吧:

[java] view plaincopy
  1. protected void doStart() throws Exception {  
  2.     _selectSet = new SelectSet[_selectSets];   //创建selectSets数组,一般情况下都是只有一个,毕竟一般都是只监听一个端口嘛  
  3.     for (int i=0;i<_selectSet.length;i++)  
  4.         _selectSet[i]= new SelectSet(i);  //创建  
  5.   
  6.     super.doStart();  
  7. }  

其实没有太多的内容,无非就是根据监听器的数量来创建selectset,那么我们来看看这个selectset的创建和它的一些重要属性吧:

[java] view plaincopy
  1. private transient int _change;  //当前用哪一个change数组,0,1里面互换  
  2. private transient List[] _changes;  //数组,用于存放需要注册到selector的channel或者任务什么的,反正就是需要一些改变的事情  
  3. private transient Timeout _idleTimeout;  //空闲的timeout任务  
  4. private transient int _nextSet;  //下一次应该放在哪一个set  
  5. private transient Timeout _retryTimeout;  
  6. private transient Selector _selector;  //nio的selector对象  
  7. private transient int _setID;     
  8. private transient boolean _selecting;  
  9. private transient int _jvmBug;  
  10.   
  11. /* ------------------------------------------------------------ */  
  12. SelectSet(int acceptorID) throws Exception { //创建来的是acceptor的编号,其实一般都是1了  
  13.     _setID=acceptorID;  
  14.   
  15.     _idleTimeout = new Timeout(this);  //创建空闲超时队列  
  16.     _idleTimeout.setDuration(getMaxIdleTime());  //  
  17.     _retryTimeout = new Timeout(this); //创建超市  
  18.     _retryTimeout.setDuration(0L);  //默认的保底持续时间0  
  19.   
  20.     // create a selector;  
  21.     _selector = Selector.open();  //创建selector  
  22.     _changes = new ArrayList[] {new ArrayList(),new ArrayList()};  //changes变量,用于保存需要注册人的channel  
  23.     _change=0;  
  24. }  

这里可以看到比较重要的selector的创建了。。也就可以知道,真正的select的流程是在selectSet里面执行的。。。

这里比较有意思的是change数组,它其实是用于临时保存所有的一些改动,例如selectkey上面关心的事件啥的。。。所有的这些改动都会在select执行之前被更新。。。

好了,SelectManager的启动就先到这吧,

回到上面,来看看SelectConnecor的open方法吧:

[java] view plaincopy
  1. //这里用于打开监听,创建serversocketchannel,并且还要将其设置为非阻塞的  
  2.  public void open() throws IOException {  
  3.      synchronized(this) {  
  4.          if (_acceptChannel == null) {  
  5.              // Create a new server socket  
  6.              _acceptChannel = ServerSocketChannel.open();  //创建serversocketchannel  
  7.   
  8.              // Bind the server socket to the local host and port  
  9.              _acceptChannel.socket().setReuseAddress(getReuseAddress());  
  10.              InetSocketAddress addr = getHost()==null?new InetSocketAddress(getPort()):new InetSocketAddress(getHost(),getPort());  
  11.              _acceptChannel.socket().bind(addr,getAcceptQueueSize());  
  12.   
  13.              // Set to non blocking mode  
  14.              _acceptChannel.configureBlocking(false);  //设置为非阻塞的模式  
  15.                
  16.          }  
  17.      }  
  18.  }  

这里其实就可以看到首先是创建了serversocketChannel,然后设置了它的地址啥的。。最后还将其设置为非阻塞。。。那么接下来就应该看看它是如何被注册到selector上面去了。。。 _manager.register(_acceptChannel);

[java] view plaincopy
  1. _manager.register(_acceptChannel);  
[java] view plaincopy
  1. //在selector上面注册ServerChannel,其实是将其放到SelectSet上面去  
  2. public void register(ServerSocketChannel acceptChannel) throws IOException {  
  3.     int s=_set++;   
  4.     s=s%_selectSets;  
  5.     SelectSet set=_selectSet[s];  //获取用于注册这个serversocketchanneld额selectSet  
  6.     set.addChange(acceptChannel);//将这个channel放到这个selectSet的change数组里面,待会会将其注册到selector上面  
  7.     set.wakeup();  
  8. }  


这里其实可以看到并没有真正的立即将这个channel注册到selector上面去,而是先将其放到selectSet的change数组。。那么待会看select的流程的时候,在select执行之前,它将会被注册到selector上面去。。。

好了,这里先暂时不看。。

回到上面。。来看看父类的doStart方法干了什么事情吧:

[java] view plaincopy
  1. //用于当前组件的启动,这里还会启动线程,用于接收远程的连接请求  
  2. protected void doStart() throws Exception {  
  3.     if (_server==null)  
  4.         throw new IllegalStateException("No server");  
  5.     //开启监听  
  6.     open();  
  7.       
  8.     super.doStart();  //父类的启动,其实也就是abstractBuffer的启动  
  9.       
  10.     if (_threadPool==null)  
  11.         _threadPool=_server.getThreadPool();  //这里相当于是获取线程池  
  12.     if (_threadPool!=_server.getThreadPool() && (_threadPool instanceof LifeCycle))  
  13.         ((LifeCycle)_threadPool).start();   //线程池的启动  
  14.       
  15.     // Start selector thread  
  16.     synchronized(this)  
  17.     {  
  18.         _acceptorThread=new Thread[getAcceptors()];  //用于运行监听器的线程数组,当具体的在线程池中运行了以后才会具体设置线程,这里其实一般就是一个监听器  
  19.   
  20.         for (int i=0;i<_acceptorThread.length;i++)  
  21.         {  
  22.             if (!_threadPool.dispatch(new Acceptor(i)))  //这里相当于是将监听器运行起来  
  23.             {  
  24.                 Log.warn("insufficient maxThreads configured for {}",this);  
  25.                 break;  
  26.             }  
  27.         }  
  28.     }  
  29.       
  30.     Log.info("Started {}",this);  
  31. }  

这段代码就是我们以前分析过的了,它将会创建一个Acceptor对象,然后在threadPool里面调度它,而他要做的事情很简单,就是不断的执行在子类中实现的accept方法。。。。那么我们来看看SelectConnector中定义的accept方法吧:

[java] view plaincopy
  1. //将会有一个线程不断的调用这个方法,其实是执行select的流程。。  
  2. public void accept(int acceptorID) throws IOException {  
  3.     _manager.doSelect(acceptorID);  //其实是调用manager来处理的,这里参数就是1 吧  
  4. }  

其实这里又是直接调用的selectManager的doSelect方法。。那么继续来看看吧:

[java] view plaincopy
  1. //这里其实实际是调用selectSet来处理select的,一般情况下一个ServerSocketChannle对应一个selectSet  
  2. public void doSelect(int acceptorID) throws IOException {  //id就是对应要用select的set  
  3.     SelectSet[] sets= _selectSet;  
  4.     if (sets!=null && sets.length>acceptorID && sets[acceptorID]!=null)  
  5.         sets[acceptorID].doSelect();  //执行select  
  6. }  

好吧,其实又是调用的selectSet的doSelect方法。。。那么我们来看看这个方法吧(它就是整个select的执行流程):

[java] view plaincopy
  1. public void doSelect() throws IOException  {  
  2.     SelectionKey key=null;  
  3.       
  4.     try {  
  5.         List changes;  
  6.         synchronized (_changes)  
  7.         {  
  8.             changes=_changes[_change]; //获取应该select的对象  
  9.             _change=_change==0?1:0;  //在0,1两个数组里面轮换  
  10.             _selecting=true;  //表示正在执行select  
  11.         }  
  12.   
  13.         // Make any key changes required  
  14.         //这里遍历change数组里面的所有,将他们注册到selector上面去,或者是其他的类型,那么做相应的动作就好了  
  15.         //有serversocket的注册,key的事件更新,任务的调度啥的  
  16.         for (int i = 0; i < changes.size(); i++) {  
  17.             try  
  18.             {  
  19.                 Object o = changes.get(i);  
  20.                 if (o instanceof EndPoint) {  //一般在httpconnection的handle方法执行完毕之后,如果有需要,那么都会挂起doUpdateKey方法,用于在select之前更新注册的事件  
  21.                     SelectChannelEndPoint endpoint = (SelectChannelEndPoint)o;  
  22.                     endpoint.doUpdateKey();  //更新它的key,其实是更新它注册的事件  
  23.                 } else if (o instanceof Runnable)  {  
  24.                     dispatch((Runnable)o);   //执行这个runnable  
  25.                 } else if (o instanceof SocketChannel) {  
  26.                     // finish accepting/connecting this connection  
  27.                     SocketChannel channel=(SocketChannel)o;  
  28.                     Object att = changes.get(++i);  //获取attachMent  
  29.   
  30.                     if (channel.isConnected())  {  //如果已经连接了,那么注册它的读取事件  
  31.                         key = channel.register(_selector,SelectionKey.OP_READ,att); //这里是注册读事件  
  32.                         SelectChannelEndPoint endpoint = newEndPoint(channel,this,key);  //创建selectChannelConnector里面定义的ConnectorEndPoint  
  33.                         key.attach(endpoint);  
  34.                         endpoint.dispatch();  //它本来也是一个runnable,run方法是执行httpconnection的handle方法  
  35.                     }  else {  //注册它的connect事件  
  36.                         channel.register(_selector,SelectionKey.OP_CONNECT,att);  
  37.                     }  
  38.   
  39.                 }  else if (o instanceof ServerSocketChannel)  {   
  40.                     ServerSocketChannel channel = (ServerSocketChannel)o;  //如果是serversocketchannel,那么需要祖册它的accept事件  
  41.                     channel.register(getSelector(),SelectionKey.OP_ACCEPT);  //将当前的serversocketchannel注册到这个selector上面去  
  42.                 } else {  
  43.                     throw new IllegalArgumentException(o.toString());  
  44.                 }  
  45.             } catch (CancelledKeyException e)  {  
  46.                 if (isRunning())  
  47.                     Log.warn(e);  
  48.                 else  
  49.                     Log.debug(e);  
  50.             }  
  51.         }  
  52.           
  53.         changes.clear();  //用于将change队列里面的需要注册的channel都清除,因为已经注册到上面去了,或者应该走的事情都已经做完了  
  54.   
  55.         long idle_next = 0;  
  56.         long retry_next = 0;  
  57.         long now=System.currentTimeMillis();  //记录select之前的时间  
  58.         synchronized (this) {  
  59.             _idleTimeout.setNow(now);  //设置timeOut队列的当前时间  
  60.             _retryTimeout.setNow(now);  
  61.             if (_lowResourcesConnections>0 && _selector.keys().size()>_lowResourcesConnections)  
  62.                 _idleTimeout.setDuration(_lowResourcesMaxIdleTime);  
  63.             else   
  64.                 _idleTimeout.setDuration(_maxIdleTime);  
  65.             idle_next=_idleTimeout.getTimeToNext();  //获取下一个即将超时的时间还有多久  
  66.             retry_next=_retryTimeout.getTimeToNext();  
  67.         }  
  68.   
  69.        //这里用于计算select的阻塞时间  
  70.         long wait = 1000L;  // not getMaxIdleTime() as the now value of the idle timers needs to be updated.  
  71.         if (idle_next >= 0 && wait > idle_next)  
  72.             wait = idle_next;  
  73.         if (wait > 0 && retry_next >= 0 && wait > retry_next)  
  74.             wait = retry_next;  
  75.   
  76.         // Do the select.  
  77.         if (wait > 10) {// TODO tune or configure this  
  78.             long before=now;  
  79.             int selected=_selector.select(wait);  
  80.             now = System.currentTimeMillis();  //更新select之后的时间  
  81.             _idleTimeout.setNow(now);  //重新设置timeout队列的时间  
  82.             _retryTimeout.setNow(now);  
  83.   
  84.             // Look for JVM bug   
  85.             if (selected==0 && wait>0 && (now-before)<wait/2 && _selector.selectedKeys().size()==0)  
  86.             {  
  87.                 if (_jvmBug++>5)  // TODO tune or configure this  
  88.                 {  
  89.                     // Probably JVM BUG!  
  90.                       
  91.                     Iterator iter = _selector.keys().iterator();  
  92.                     while(iter.hasNext())  
  93.                     {  
  94.                         key = (SelectionKey) iter.next();  
  95.                         if (key.isValid()&&key.interestOps()==0)  
  96.                         {  
  97.                             key.cancel();  
  98.                         }  
  99.                     }  
  100.                     try  
  101.                     {  
  102.                         Thread.sleep(20);  // tune or configure this  
  103.                     }  
  104.                     catch (InterruptedException e)  
  105.                     {  
  106.                         Log.ignore(e);  
  107.                     }  
  108.                 }   
  109.             }  
  110.             else  
  111.                 _jvmBug=0;  
  112.         }  else  {  
  113.             _selector.selectNow();  
  114.             _jvmBug=0;  
  115.         }  
  116.   
  117.         // have we been destroyed while sleeping\  
  118.         if (_selector==null || !_selector.isOpen())  
  119.             return;  
  120.   
  121.         // Look for things to do  
  122.         Iterator iter = _selector.selectedKeys().iterator();  
  123.         //遍历所有已经select出来的key  
  124.         while (iter.hasNext())  {  
  125.             key = (SelectionKey) iter.next();                        
  126.             try  {  
  127.                 if (!key.isValid()) {  
  128.                     key.cancel();  //用于取消这个key的注册  
  129.                     SelectChannelEndPoint endpoint = (SelectChannelEndPoint)key.attachment();  
  130.                     if (endpoint != null)  
  131.                         endpoint.doUpdateKey();  
  132.                     continue;  
  133.                 }  
  134.   
  135.                 Object att = key.attachment();  
  136.                 if (att instanceof SelectChannelEndPoint) {  
  137.                     SelectChannelEndPoint endpoint = (SelectChannelEndPoint)att;  
  138.                     endpoint.dispatch();  //其实也就是调用SelectChannelEndPoint的run方法,其实也就是调用httpConnection的处理流程  
  139.                 } else if (key.isAcceptable()) {  //如果是accept事件  
  140.                     SocketChannel channel = acceptChannel(key); //这里相当于接收到一个socketChannel  
  141.                     if (channel==null)  
  142.                         continue;  
  143.   
  144.                     channel.configureBlocking(false);  //设置为非阻塞  
  145.   
  146.                     _nextSet=++_nextSet%_selectSet.length;  //计算下一个应该注册到哪一个selectSet上面去  
  147.   
  148.                     if (_nextSet==_setID)  {  //一般也都是相等的  
  149.                         //其实这里一般情况下selectSet的长度都是1,所以这里搞一个selector的负载均衡貌似也没啥用啊。。  
  150.                         SelectionKey cKey = channel.register(_selectSet[_nextSet].getSelector(), SelectionKey.OP_READ);  //将其注册到selector上面去  
  151.                         SelectChannelEndPoint endpoint=newEndPoint(channel,_selectSet[_nextSet],cKey);  //创建endPoint,也就是selectChannelConnector里面定义的ConnectorEndPoint  
  152.                         cKey.attach(endpoint);   //将这个endPoint附着在上面  
  153.                         if (endpoint != null)  
  154.                             endpoint.dispatch();  //其实是执行http的流程处理  
  155.                     } else {  
  156.                         // nope - give it to another.  
  157.                         _selectSet[_nextSet].addChange(channel);  //到这个selectSet上面注册这个channel  
  158.                         _selectSet[_nextSet].wakeup();  
  159.                     }  
  160.                 }  else if (key.isConnectable()) {  //表示连接已经建立好了  
  161.                     // Complete a connection of a registered channel  
  162.                     SocketChannel channel = (SocketChannel)key.channel();  
  163.                     boolean connected=false;  
  164.                     try   {  
  165.                         connected=channel.finishConnect();  //完成连接  
  166.                     }  
  167.                     catch(Exception e)  {  
  168.                         connectionFailed(channel,e,att);  
  169.                     }  
  170.                     finally  
  171.                     {  
  172.                         if (connected) {  //表示连接已经建立了  
  173.                             key.interestOps(SelectionKey.OP_READ);  
  174.                             SelectChannelEndPoint endpoint = newEndPoint(channel,this,key);  //这里用于创建selectChannelConnector里面定义的ConnectorEndPoint  
  175.                             key.attach(endpoint);  
  176.                             endpoint.dispatch();  
  177.                         }  else {  
  178.                             key.cancel();  //取消这个key的注册  
  179.                         }  
  180.                     }  
  181.                 } else {  
  182.                     SocketChannel channel = (SocketChannel)key.channel();  
  183.                     SelectChannelEndPoint endpoint = newEndPoint(channel,this,key);  //这里有多个地方都有创建endpoint的代码,可能也是因为注册的时候稍微混乱了一些不得不这样吧  
  184.                     key.attach(endpoint);  
  185.                     if (key.isReadable())  
  186.                         endpoint.dispatch();                             
  187.                 }  
  188.                 key = null;  
  189.             }  
  190.             catch (CancelledKeyException e)  
  191.             {  
  192.                 Log.ignore(e);  
  193.             }  
  194.             catch (Exception e)  
  195.             {  
  196.                 if (isRunning())  
  197.                     Log.warn(e);  
  198.                 else  
  199.                     Log.ignore(e);  
  200.   
  201.                 if (key != null && !(key.channel() instanceof ServerSocketChannel) && key.isValid())  
  202.                 {  
  203.                     key.interestOps(0);  
  204.   
  205.                     key.cancel();  
  206.                 }   
  207.             }  
  208.         }  
  209.           
  210.         // Everything always handled  
  211.         _selector.selectedKeys().clear();  //清除那些已经选出来的key  
  212.   
  213.         // tick over the timers  
  214.         _idleTimeout.tick(now);  //执行timeout里面的超时  
  215.         _retryTimeout.tick(now);  
  216.           
  217.     }  
  218.     catch (CancelledKeyException e)  
  219.     {  
  220.         Log.ignore(e);  
  221.     }  
  222.     finally  
  223.     {  
  224.         synchronized(this)  
  225.         {  
  226.             _selecting=false;  
  227.         }  
  228.     }  
  229. }  

这部分的代码就属于比较关键的了,它执行了整个select的流程,

(1)在select之前,还先遍历了change数组,执行了一些更新的动作,前面说到的serversocketchannel的注册也将会在这里被搞定。。

(2)对于select出来的key,会对他们进行处理。。当然这里如果是SelectChannelEndPoint,那么直接就将其进行调度运行就好了。如果是accept事件,那么还需要accept的流程。。

(3)在这些搞定以后,还会进行超时的处理。。貌似所有的都是这么实现的吧。包括nginx都是在select之后进行超时的处理。。

这部分代码很多。。而且很重要。。。有很多的细节。。。这里就不一一解释了。。

先来看看accept吧:

[java] view plaincopy
  1. else if (key.isAcceptable()) {  //如果是accept事件  
  2.                             SocketChannel channel = acceptChannel(key); //这里相当于接收到一个socketChannel  
  3.                             if (channel==null)  
  4.                                 continue;  
  5.   
  6.                             channel.configureBlocking(false);  //设置为非阻塞  
  7.   
  8.                             _nextSet=++_nextSet%_selectSet.length;  //计算下一个应该注册到哪一个selectSet上面去  
  9.   
  10.                             if (_nextSet==_setID)  {  //一般也都是相等的  
  11.                                 //其实这里一般情况下selectSet的长度都是1,所以这里搞一个selector的负载均衡貌似也没啥用啊。。  
  12.                                 SelectionKey cKey = channel.register(_selectSet[_nextSet].getSelector(), SelectionKey.OP_READ);  //将其注册到selector上面去  
  13.                                 SelectChannelEndPoint endpoint=newEndPoint(channel,_selectSet[_nextSet],cKey);  //创建endPoint,也就是selectChannelConnector里面定义的ConnectorEndPoint  
  14.                                 cKey.attach(endpoint);   //将这个endPoint附着在上面  
  15.                                 if (endpoint != null)  
  16.                                     endpoint.dispatch();  //其实是执行http的流程处理  
  17.                             } else {  
  18.                                 // nope - give it to another.  
  19.                                 _selectSet[_nextSet].addChange(channel);  //到这个selectSet上面注册这个channel  
  20.                                 _selectSet[_nextSet].wakeup();  
  21.                             }  

这里调用acceptChannel方法来获取远程的链接,然后还要将其注册到selectSet上面去。。还要对这个channel进行包装,生成endpoint。。。

这个acceptChannel的方法的实现如下:

[java] view plaincopy
  1. protected SocketChannel acceptChannel(SelectionKey key) throws IOException  
  2. {  
  3.     // TODO handle max connections  
  4.     SocketChannel channel = ((ServerSocketChannel)key.channel()).accept();  //用于后去连接的channel  
  5.     if (channel==null)  
  6.         return null;  
  7.     channel.configureBlocking(false);  //将接收到的socketChannel设置为非阻塞的  
  8.     Socket socket = channel.socket();  
  9.     configure(socket);  
  10.     return channel;  
  11. }  

没啥意思,无非就是调用accept方法,获取链接,然后对获取的链接进行初始化,设置非阻塞什么的。。

这里newEndPoint方法用于创建endPoint,来看看它的实现:

[java] view plaincopy
  1. //用于创建ConnectorEndPoint  
  2. protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey sKey) throws IOException  
  3. {  
  4.     return SelectChannelConnector.this.newEndPoint(channel,selectSet,sKey);  
  5. }  

其实也就是创建ConnectorEndPoint,它的定义在SelectChannelConnector里面。。。另外在创建的过程中,其父类SelectChannelEndPoint还会创建httpConnection

这里就不详细的来讲ConnectorEndPoint的实现了。。。在前面我们可以看到在select中对于SelectChannelConnector的处理就是直接调用其dispatch方法。。。

[java] view plaincopy
  1. //调度当前这个endpoint的运行,其实是激活http的处理流程  
  2. void dispatch() throws IOException {  
  3.     boolean dispatch_done = true;  
  4.     try {  
  5.         if (dispatch(_manager.isDelaySelectKeyUpdate())) {  
  6.             dispatch_done= false;  
  7.             dispatch_done = _manager.dispatch((Runnable)this);  //相当于将交给selectorManager来处理,其实就是交给线程池里面去运行,其实是执行httpconnection的handle的方法  
  8.         }  
  9.     }  
  10.     finally {  
  11.         if (!dispatch_done) { //执行失败  
  12.             Log.warn("dispatch failed!");  
  13.             undispatch();  
  14.         }  
  15.     }  
  16. }  


这里就是在线程池中调度当前的runnable,

[java] view plaincopy
  1. //当有数据可以读的时候,会执行这个  
  2. public void run() {  
  3.     try {  
  4.         _connection.handle();  //httpConnection的方法啊  
  5.     } catch (ClosedChannelException e) {  
  6.         Log.ignore(e);  
  7.     }  catch (EofException e) {  
  8.         Log.debug("EOF", e);  
  9.         try{close();}  
  10.         catch(IOException e2){Log.ignore(e2);}  
  11.     } catch (HttpException e)  {  
  12.         Log.debug("BAD", e);  
  13.         try{close();}  
  14.         catch(IOException e2){Log.ignore(e2);}  
  15.     }  catch (Throwable e)  {  
  16.         Log.warn("handle failed", e);  
  17.         try{close();}  
  18.         catch(IOException e2){Log.ignore(e2);}  
  19.     } finally {  
  20.         undispatch();  //因为是非阻塞的,所以需要从线程池里面移除,并且还要进行key的更新,有可能需要加入新的事件  
  21.     }  
  22. }  

到这里就很熟悉了吧。。就进入了http的处理流程。。因为这里的connection其实就是httpConnection。。。


由此。。整个SelectChannelConnector的运行流程就算比较的清晰了。。。。。

首先将监听器注册到selector上,。。。当有新的连接进来之后,获取新的channel,然后将其进行包装。。变成ConnectorEndPoint,将其注册到selector上面。。。

当selector感应到上面的事件之后,就直接进行httpConnection的处理流程。。。。


同时这里也感觉整个这部分I/O的处理不是很干净。。。。如果能够用netty将下面的这部分I/O替换掉就好多了。。当然这个还是有一定难度的。。。

0 0
原创粉丝点击