• NIO系列3:TCP服务接入


    注:本文适合对象需对java NIO API的使用及异步事件模型(Reactor模式)有一定程度的了解,主要讲述使用java原生NIO实现一个TCP服务的过程及细节设计。


    前文讲述了NIO TCP服务绑定过程的实现机制,现在可以开始讲述服务监听启动后如何和处理接入和数据传输相关的细节设计。

    在NIO的接入类中有一个Reactor线程,用于处理OP_ACCEPT事件通知,如下:

      private class AcceptThread extends Thread {
    		public void run() {
    			while (selectable) {
    				try {
    					int selected = selector.select();
    					
    					if (selected > 0) {
    						accept();
    					}
    					
    					// bind addresses to listen
    					bind0();
    					
    					// unbind canceled addresses
    					unbind0();
    				} catch (Exception e) {
    					LOG.error("Unexpected exception caught while accept", e);
    				}
    			}
    			
    			// if selectable == false, shutdown the acceptor
    			try {
    				shutdown0();
    			} catch (Exception e) {
    				LOG.error("Unexpected exception caught while shutdown", e);
    			}
    		}
    	}


    当有客户端接入时selector.select()方法返回大于0的整数,并进入accept()方法进行处理,具体如下:

      private void accept() {
    		Iterator<SelectionKey> it = selector.selectedKeys().iterator();
    		while (it.hasNext()) {
    			SelectionKey key = it.next();
    			it.remove();
    			AbstractSession session = (AbstractSession) acceptByProtocol(key);
    			Processor processor = pool.get(session);
    			session.setProcessor(processor);
    			processor.add(session);
    		}
    	}


      protected Session acceptByProtocol(SelectionKey key) {
    		if (key == null || !key.isValid() || !key.isAcceptable()) {
                		return null;
            	}
    		
    		ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
    		SocketChannel sc = null;
    		try {
    			sc = ssc.accept();
    			if(sc == null) {
    				return null;
    			}
    			sc.configureBlocking(false);
    		} catch (IOException e) {
    			LOG.warn(e.getMessage(), e);
    			if(sc != null) {
    				try {
    					sc.close();
    				} catch (IOException ex) {
    					LOG.warn(ex.getMessage(), ex);
    				}
    			}
    		}
    		
    		Session session = new TcpSession(sc, config);
    		
    		return session;
    	}


    为每一个接入的客户端通过调用NIO原生accept()方法返回一个SocketChannel的抽象,并封装成一个session对象(session的概念来自mina框架)

    注意:此时与客户连接的通道尚未注册对读/写事件感兴趣,因为它的注册与前文绑定过程一样需要异步进行。

    因此将封装通道的session转交给一个processor对象(io读写处理器,该概念也是来自mina),processor内部维持了一个新建session的队列,在其内部reactor线程循环中进行注册处理。

    有关processor处理读写事件的细节设计见下文。



  • 相关阅读:
    NHibernate中多表(对象)间的查询
    将datagrid数据导到excel的一个问题
    win2003<IIS6>部署.net 4.0<asp.net 4>
    C# 单元测试
    office2010 word发布博客 博客园
    语义化的HTML首先要强调HTML结构
    SQL Server 2005 安装(各种错误)
    SWFUpload V2.2.0 说明文档
    SQL Server 复制, 集群
    高亮插件测试
  • 原文地址:https://www.cnblogs.com/hehe520/p/6147657.html
Copyright © 2020-2023  润新知