Timing diagram 1
Timing diagram 2
NioEndpoint(Key categories
)
/**
* Start the NIO endpoint, creating acceptor, poller threads.
*/
@Override
public void startInternal() throws Exception {
if (!running) {
running = true;
paused = false;
processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
socketProperties.getProcessorCache());
eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
socketProperties.getEventCache());
nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
socketProperties.getBufferPool());
// Create worker collection
if ( getExecutor() == null ) {
createExecutor();
}
initializeConnectionLatch();
// Start poller threads
pollers = new Poller[getPollerThreadCount()];
for (int i=0; i<pollers.length; i++) {
pollers[i] = new Poller();
Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i);
pollerThread.setPriority(threadPriority);
pollerThread.setDaemon(true);
pollerThread.start();
}
startAcceptorThreads();
}
}
startAcceptorThreads(Thread[http-nio-8080-Acceptor-0,5,main]
)
protected final void startAcceptorThreads() {
int count = getAcceptorThreadCount();
acceptors = new Acceptor[count];
for (int i = 0; i < count; i++) {
acceptors[i] = createAcceptor();
String threadName = getName() + "-Acceptor-" + i;
acceptors[i].setThreadName(threadName);
Thread t = new Thread(acceptors[i], threadName);
t.setPriority(getAcceptorThreadPriority());
t.setDaemon(getDaemon());
t.start();
}
}
NioEndpoint$Acceptor
// --------------------------------------------------- Acceptor Inner Class
/**
* The background thread that listens for incoming TCP/IP connections and
* hands them off to an appropriate processor.
*/
protected class Acceptor extends AbstractEndpoint.Acceptor {
@Override
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();
SocketChannel socket = null;
try {
// Accept the next incoming connection from the server
// socket
socket = serverSock.accept();
} catch (IOException ioe) {
//we didn't get a socket
countDownConnection();
// Introduce delay if necessary
errorDelay = handleExceptionWithDelay(errorDelay);
// re-throw
throw ioe;
}
// Successful accept, reset the error delay
errorDelay = 0;
// setSocketOptions() will add channel to the poller
// if successful
if (running && !paused) {
if (!setSocketOptions(socket)) {
countDownConnection();
closeSocket(socket);
}
} else {
countDownConnection();
closeSocket(socket);
}
} catch (SocketTimeoutException sx) {
// Ignore: Normal condition
} catch (IOException x) {
if (running) {
log.error(sm.getString("endpoint.accept.fail"), x);
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error(sm.getString("endpoint.accept.fail"), t);
}
}
state = AcceptorState.ENDED;
}
}
Here I see the familiar code of java network programming that I haven’t seen for a long time.
countUpOrAwaitConnection
protected void countUpOrAwaitConnection() throws InterruptedException {
if (maxConnections==-1) return;
LimitLatch latch = connectionLimitLatch;
if (latch!=null) latch.countUpOrAwait();
}
Initial value of LimitLatch (maxConnections
)
protected LimitLatch initializeConnectionLatch() {
if (maxConnections==-1) return null;
if (connectionLimitLatch==null) {
connectionLimitLatch = new LimitLatch(getMaxConnections());
}
return connectionLimitLatch;
}
Above this value, the request has been waiting since it came in, i.e. the connection is piled up in the accept queue and the service cannot be obtained.
Details of TCP three-way handshake Connection Establishment in socket
When the client calls connect, it triggers the connection request and sends SYN J packet to the server, then connect enters the blocking state. The server listens to the connection request, namely receives the SYN J packet, calls the accept function to receive the request and sends SYN K, ACK J+1 to the client, then accept enters the blocking state; After the client receives the SYN K and ACK J+1 from the server, connect returns and confirms the SYN K. When the server receives ACK K+1, accept returns, thus completing the three-way handshake and establishing the connection.
The client’s connect returned for the second time in three-way handshake, while the server’s accept returned for the third time in three-way handshake.
Socket Layer Execution Logic in three-way handshake
三次握手建立TCP连接的流程如下:
C(Browser) S(www.baidu.com)
1. CLOSED LISTEN
2. SYN-SENT →<SEQ=0><CTL=SYN> → SYN-RECEIVED
3. ESTABLISHED← <SEQ=0><ACK=1><CTL=SYN,ACK> ← SYN-RECEIVED
4. ESTABLISHED→ <SEQ=1><ACK=1><CTL=ACK> → ESTABLISHED
3-Way Handshake for Connection Synchronization
S calls the listen function of socket to enter listening state; C calls connect function to connect S: [SYN], S calls accept function to accept C’s connection and initiate connection with C direction: [SYN,ACK]. C Send [ACK] to complete three-way handshake, connect function returns; After s receives [ACK] from c, the accept function returns.