getprivateprofilestring读不到数据_Tomcat NIO(11)请求数据读取
對于 tomcat 請求數據的讀取來說,可以分為請求行的讀取,請求頭的讀取,請求體的讀取,三個部分方法調用序列圖如下:
讀取請求行讀取請求頭讀取請求體綜合上面三個序列圖,對于請求行,請求頭,請求體的讀取都最終調用了NioSocketWrapper 對象實例的 fillReadBuffer() 方法。只不過請求行和請求頭讀取參數傳遞為 true,請求體讀取參數傳遞為 false,該方法核心代碼如下:
private int fillReadBuffer(boolean block, ByteBuffer to) throws IOException { int nRead; NioChannel socket = getSocket(); if (socket instanceof ClosedNioChannel) { throw new ClosedChannelException(); } if (block) { Selector selector = null; try { selector = pool.get(); } catch (IOException x) { // Ignore } try { nRead = pool.read(to, socket, selector, getReadTimeout()); } finally { if (selector != null) { pool.put(selector); } } } else { nRead = socket.read(to); if (nRead == -1) { throw new EOFException(); } } return nRead;}- 根據上述方法分析,對于請求行和請求頭的讀取采用非阻塞的方式,用到了以前文章介紹的 NioChannel 對象的 read(ByteBuffer) 方法,其核心代碼如下:
- 根據上述代碼,請求行和請求頭的讀取本質是調用 java NIO api SocketChannel 的 read() 方法,該方法為非阻塞方法。如果讀不到數據就直接返回,繼續由以前文章介紹的 poller 線程監測是否有數據可讀。
對于請求體的讀取采用阻塞的方式,調用以前文章中介紹的 NioSelectorPool 的read(ByteBuffer buf, NioChannel socket, Selector selector, long readTimeout) 方法。在該方法中又會調用 NioBlockingSelector 的 read() 方法,核心代碼如下:
public int read(ByteBuffer buf, NioChannel socket, long readTimeout) throws IOException { SelectionKey key = socket.getIOChannel().keyFor(socket.getSocketWrapper().getPoller().getSelector()); if (key == null) { throw new IOException(sm.getString("nioBlockingSelector.keyNotRegistered")); } KeyReference reference = keyReferenceStack.pop(); if (reference == null) { reference = new KeyReference(); } NioSocketWrapper att = (NioSocketWrapper) key.attachment(); int read = 0; boolean timedout = false; int keycount = 1; //assume we can read long time = System.currentTimeMillis(); //start the timeout timer try { while (!timedout) { if (keycount > 0) { //only read if we were registered for a read read = socket.read(buf); if (read != 0) { break; } } try { if (att.getReadLatch()==null || att.getReadLatch().getCount()==0) { att.startReadLatch(1); } poller.add(att,SelectionKey.OP_READ, reference); att.awaitReadLatch(AbstractEndpoint.toTimeout(readTimeout), TimeUnit.MILLISECONDS); } catch (InterruptedException ignore) { // Ignore } if ( att.getReadLatch()!=null && att.getReadLatch().getCount()> 0) { //we got interrupted, but we haven't received notification from the poller. keycount = 0; }else { //latch countdown has happened keycount = 1; att.resetReadLatch(); } if (readTimeout >= 0 && (keycount == 0)) { timedout = (System.currentTimeMillis() - time) >= readTimeout; } } if (timedout) { throw new SocketTimeoutException(); } } finally { poller.remove(att,SelectionKey.OP_READ); if (timedout && reference.key != null) { poller.cancelKey(reference.key); } reference.key = null; keyReferenceStack.push(reference); } return read;}- 根據以上代碼整個讀數據邏輯在一個循環里進行,如果有數據讀到就跳出循環,返回數據。
- 如果沒有數據,則調用 BlockPoller 的 add() 方法,該方法將封裝的 OP_READ 事件添加到 BlockPoller 的事件隊列里。關于 BlockPoller 我們在后面文章里詳細講解。
- 然后在調用以前文章介紹的 NioSocketWrapper 中的 CountDownLatch 類型 readLatch 屬性的 await() 方法,使當前線程(一般是tomcat io線程)在 readLatch 上等待。
當前線程在 readLatch 上等待一般有超時時間(讀超時時間),默認不配置為 -1,這時超時時間為 Long.MAX_VALUE 毫秒。
對于 tomcat 數據讀取總結如下:
對于請求行,請求頭和請求體的讀取默認(不開啟異步)都在 tomcat io 線程中進行。
對于請求行和請求頭的讀取是非阻塞讀取,即不阻塞 tomcat io 線程,如果沒有讀取到數據,則由 poll 線程繼續監測下次數據的到來。
對于請求體的讀取是阻塞的讀取,如果發現請求體數據不可讀,那么首先注冊封裝的 OP_READ 事件到 BlockPoller 對象實例的事件隊列里。然后利用 NioSocketWrapper 對象中的 readLatch 來阻塞 tomcat io 線程。
對于 tomcat io 線程阻塞時間為讀超時,默認不配置為 -1,這時超時時間為 Long.MAX_VALUE 毫秒。
如果超時,則拋出 SocketTimeoutException,并取消上面注冊的讀事件。
最后將該事件從 selector 中移除(一般是可讀事件)。
目前先寫到這里,下一篇文章里我們繼續介紹 tomcat 中的響應數據的寫入。
總結
以上是生活随笔為你收集整理的getprivateprofilestring读不到数据_Tomcat NIO(11)请求数据读取的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 陕西2021高考成绩在哪查询,2021陕
- 下一篇: java中的de是什么_【转】java中