NIOシリーズ3:TCPサービスアクセス

2512 ワード

注意:本明細書の適合対象はjava NIO APIの使用および非同期イベントモデル(Reactorモード)についてある程度理解する必要があり、主にjava原生NIOを使用してTCPサービスを実現する過程と詳細設計について述べる.
前述したNIO TCPサービスバインディングプロセスの実装メカニズムについて説明したが、サービスリスニングの開始後、アクセスとデータ伝送の処理に関する詳細な設計を開始することができる.
NIOのアクセスクラスには、OP_を処理するためのReactorスレッドがあります.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の抽象を返し、セッションオブジェクトにカプセル化する(セッションの概念はminaフレームワークから来ている)
注:この時点で、お客様と接続されているチャネルは、前述のバインドプロセスと同様に非同期で登録する必要があるため、読み取り/書き込みイベントに興味がありません.
したがって、カプセル化チャネルのsessionは、minaからの概念でもあるprocessorオブジェクト(io読み書きプロセッサ)に渡され、processor内部には新しいsessionのキューが維持され、その内部reactorスレッドループで登録処理が行われる.
プロセスが読み書きイベントを処理する詳細については、以下を参照してください.