浅析Tomcat之JIoEndpoint

AbstractEndpoint是基础的通信端点的实现,那么也就有具体的实现.其中一个就是JIoEndpoint,它的作用是处理访问的TCP连接.具体的实现是主线程启动一个Acceptor线程,它将启用一个阻塞型Socket侦听Tcp连接,获得连接后对每个连接启动一个worker线程进行处理.这是一个典型的Listen-Accept-Handle实现.

先看下它是怎么实现AbstractEndPoint的Acceptor,它简单的实现了一个run方法.这个线程在生命周期的init中将被启动.

public void run() {

	int errorDelay = 0;

	// Loop until we receive a shutdown command
	while (running) {

		// Loop if endpoint is paused
		while (paused && running) {
			state = AcceptorState.PAUSED;
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				// Ignore
			}
		}

		if (!running) {
			break;
		}
		state = AcceptorState.RUNNING;

		try {
			//if we have reached max connections, wait
			countUpOrAwaitConnection();

			Socket socket = null;
			try {
				// Accept the next incoming connection from the server
				// socket
				socket = serverSocketFactory.acceptSocket(serverSocket);
			} catch (IOException ioe) {
				countDownConnection();
				// Introduce delay if necessary
				errorDelay = handleExceptionWithDelay(errorDelay);
				// re-throw
				throw ioe;
			}
			// Successful accept, reset the error delay
			errorDelay = 0;

			// Configure the socket
			if (running && !paused && setSocketOptions(socket)) {
				// Hand this socket off to an appropriate processor
				if (!processSocket(socket)) {
					countDownConnection();
					// Close socket right away
					closeSocket(socket);
				}
			} else {
				countDownConnection();
				// Close socket right away
				closeSocket(socket);
			}
		} catch (IOException x) {
			if (running) {
				log.error(sm.getString("endpoint.accept.fail"), x);
			}
		} catch (NullPointerException npe) {
			if (running) {
				log.error(sm.getString("endpoint.accept.fail"), npe);
			}
		} catch (Throwable t) {
			ExceptionUtils.handleThrowable(t);
			log.error(sm.getString("endpoint.accept.fail"), t);
		}
	}
	state = AcceptorState.ENDED;
}

 从上面代码看出,最外层的while是一直存在的,除非服务器不是运行状态.而while (paused && running) 是标志着这个端点处于暂停服务状态.如果countUpOrAwaitConnection线程没有进入等待队列的话就接受socket,也就是接受TCP连接请求.这里的Socket是阻塞Socket.正因为是阻塞的Socket,所以需要多线程处理.也就是所谓的worker线程,下面看下processSocket方法.

protected boolean processSocket(Socket socket) {
	// Process the request from this socket
	try {
		SocketWrapper<socket> wrapper = new SocketWrapper<socket>(socket);
		wrapper.setKeepAliveLeft(getMaxKeepAliveRequests());
		// During shutdown, executor may be null - avoid NPE
		if (!running) {
			return false;
		}
		getExecutor().execute(new SocketProcessor(wrapper));
	} catch (RejectedExecutionException x) {
		log.warn("Socket processing request was rejected for:"+socket,x);
		return false;
	} catch (Throwable t) {
		ExceptionUtils.handleThrowable(t);
		// This means we got an OOM or similar creating a thread, or that
		// the pool and its queue are full
		log.error(sm.getString("endpoint.process.fail"), t);
		return false;
	}
	return true;
}

   processSocket对新的连接进行处理.但是很显然它所做的仅仅是Socket的包装和异常处理.还有启动work线程.也就是SocketProcessor.该方法的注释是Process a new connection from a new client. Wraps the socket so keep-alive and other attributes can be tracked and then passes the socket to the executor for processing.下面看下worker线程(SocketProcessor)的run方法实现.

public void run() {
	boolean launch = false;
	synchronized (socket) {
		try {
			SocketState state = SocketState.OPEN;

			try {
				// SSL handshake
				serverSocketFactory.handshake(socket.getSocket());
			} catch (Throwable t) {
				ExceptionUtils.handleThrowable(t);
				if (log.isDebugEnabled()) {
					log.debug(sm.getString("endpoint.err.handshake"), t);
				}
				// Tell to close the socket
				state = SocketState.CLOSED;
			}

			if ((state != SocketState.CLOSED)) {
				if (status == null) {
					state = handler.process(socket, SocketStatus.OPEN);
				} else {
					state = handler.process(socket,status);
				}
			}
			if (state == SocketState.CLOSED) {
				// Close socket
				if (log.isTraceEnabled()) {
					log.trace("Closing socket:"+socket);
				}
				countDownConnection();
				try {
					socket.getSocket().close();
				} catch (IOException e) {
					// Ignore
				}
			} else if (state == SocketState.OPEN ||
					state == SocketState.UPGRADING  ||
					state == SocketState.UPGRADED){
				socket.setKeptAlive(true);
				socket.access();
				launch = true;
			} else if (state == SocketState.LONG) {
				socket.access();
				waitingRequests.add(socket);
			}
		} finally {
			if (launch) {
				try {
					getExecutor().execute(new SocketProcessor(socket, SocketStatus.OPEN));
				} catch (RejectedExecutionException x) {
					log.warn("Socket reprocessing request was rejected for:"+socket,x);
					try {
						//unable to handle connection at this time
						handler.process(socket, SocketStatus.DISCONNECT);
					} finally {
						countDownConnection();
					}

				} catch (NullPointerException npe) {
					if (running) {
						log.error(sm.getString("endpoint.launch.fail"),
								npe);
					}
				}
			}
		}
	}
	socket = null;
	// Finish up this request
}

   方法这么长key point就一个地方state = handler.process(socket,status).这个handler继承了AbstractEndpoint的Handler这个Handler还是没有给出具体的实现.具体的实现在具体的Protocol中.可以确定的是,它的实现应该有个轮询处理.知道了Acceptor和和Worker.那就看看他们的生命周期.生命周期函数是实现了父类AbstractEndpoint的抽象方法.

public void bind() throws Exception {

	// Initialize thread count defaults for acceptor
	if (acceptorThreadCount == 0) {
		acceptorThreadCount = 1;
	}
	// Initialize maxConnections
	if (getMaxConnections() == 0) {
		// User hasn't set a value - use the default
		setMaxConnections(getMaxThreadsExecutor(true));
	}

	if (serverSocketFactory == null) {
		if (isSSLEnabled()) {
			serverSocketFactory =
				handler.getSslImplementation().getServerSocketFactory(this);
		} else {
			serverSocketFactory = new DefaultServerSocketFactory(this);
		}
	}

	if (serverSocket == null) {
		try {
			if (getAddress() == null) {
				serverSocket = serverSocketFactory.createSocket(getPort(),
						getBacklog());
			} else {
				serverSocket = serverSocketFactory.createSocket(getPort(),
						getBacklog(), getAddress());
			}
		} catch (BindException orig) {
		   ......
		}
	}

}

   bind主要是初始化acceptor的线程数,这里是1.最大连接数和创建ServerSocket.接着是startInternal方法.它的作用是创建Worker线程池,连接限制锁存器.还有启动Acceptor线程.最后值得一提的是它启动了一个timeoutThread.这是一个对连接超时进行处理的线程.有了Acceptor,Worker和TimeoutThread.这样JIoEndpoint在生命周期内就能接受TCP连接,并转发给Handler处理.

 

 

首发于泛泛之辈 - http://www.lihongkun.com/archives/113

猜你喜欢

转载自lihkstyle.iteye.com/blog/1944401
今日推荐