在上一篇文章里我们主要介绍了 tomcat io 线程中涉及到的主要核心类,包括 AbstractProcessorLight,Http11Processor,CoyoteAdapter,这里主要介绍对于请求数据的读取。

对于 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) 方法,其核心代码如下:
//NioChannelprotected SocketChannel scpublic int read(ByteBuffer dst) throws IOException {    return sc.read(dst); }
  • 根据上述代码,请求行和请求头的读取本质是调用 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)请求数据读取相关推荐

  1. PostgreSQL 10.1 手册_部分 II. SQL 语言_第 5 章 数据定义_5.11. 外部数据

    5.11. 外部数据 PostgreSQL实现了部分的SQL/MED规定,允许我们使用普通SQL查询来访问位于PostgreSQL之外的数据.这种数据被称为外部数据(注意这种用法不要和外键混淆,后者是 ...

  2. java删除页面数据不刷新_Ajax请求数据与删除数据后刷新页面

    1.ajax异步请求数据后填入模态框 请求数据的按钮(HTML) ajax异步请求数据后给id为queryInfo的模态框赋值并弹出模态框(JS) //查询单个 functionquery(id) { ...

  3. R包自带数据汇总(自带数据包:datasets)

    更新中 ... ... 引言 1.原子向量 + 条形图(一维) 1.1 欧元货币换算率 1.2 美国城市年降水量 1.3 北美主要河流的长度(不含河流名字) 1.4美国50个州信息(缩写.名称.全称) ...

  4. MongoDB 数据操作(二)数据查询(10)正则运算

    来源:我的博客站 OceanicKang |<MongoDB 数据操作(二)数据查询(10)正则运算> 上一篇:<MongoDB 数据操作(二)数据查询(9)条件过滤> 如果要 ...

  5. Angular中使用HttpClientModule模块实现get请求数据和post提交数据

    场景 Angular介绍.安装Angular Cli.创建Angular项目入门教程: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/detail ...

  6. 怎么调用获取被创建的预制体_Go 语言 Web 编程系列—— 获取用户请求数据(上)...

    0.GET/POST 请求数据 在 PHP 中,可以直接通过全局变量 $_GET 和 $_POST 快速获取 GET/POST 请求数据,GET 请求数据主要是 URL 查询字符串中包含的参数,以前面 ...

  7. 通过Ajax异步请求数据

    通过XMLHttpRequest对象的send()方法实现 <!DOCTYPE html> <html lang="en"> <head>< ...

  8. vue三种ajax请求方式,vue请求数据的三种方式

    请求数据的方式: vue-resource 官方提供的 vue的一个插件 axios fetch-jsonp 一,vue-resource请求数据 介绍:vue-resource请求数据方式是官方提供 ...

  9. vue中使用axios请求数据过程

    使用axios请求数据过程 1. 导入axios包 import axios from 'axios' 2. 在钩子函数中调用函数 mounted() {this.getinitialdata() / ...

最新文章

  1. 【安全加密技术】 对称加密
  2. 【BZOJ】3173: [Tjoi2013]最长上升子序列(树状数组)
  3. java二期_Java架构师鲁班二期
  4. 应用计算机测定线性电阻伏安特性实验器材,线性电阻与非线性电阻伏安特性实验的Origin处理...
  5. 安卓手机能用signal吗_现在的安卓手机可以直接更新成鸿蒙系统吗?还是必须购买新的手机?...
  6. P4513 小白逛公园 (线段树)
  7. 听说”双11”是这么解决线上bug的
  8. python中的[-1]、[:-1]、[::-1]、[n::-1]
  9. springboot 静态资源访问
  10. 【挖坑系列】关于浏览器の缓存机制
  11. 【技术白皮书】第四章:信息抽取技术产业应用现状及案例(下)
  12. 淘宝店铺上传成人用品类宝贝的错误解决
  13. linux的第一个逻辑分区表示为 ?,/dev/sda5 在 Linux 中表示 答案:第一块SCIS 硬盘上的逻辑分区...
  14. 修改elemntui tabs 下划线长短
  15. MBR10200FAC-ASEMI塑封肖特基二极管MBR10200FAC
  16. (ง •_•)ง[Python3 OpenCV4]10.平滑图像
  17. 南大庄建军计算机学院讲座,南京大学庄建军来校进行双创教育交流
  18. Result「?」 返回类型拼接
  19. 大鱼吃小鱼游戏代码 基于java-swing
  20. 一条视频涨粉10万+,情侣账号如何实现流量、变现两不误?

热门文章

  1. 弹跳机器人 桌游_MIT机器人轻松搞定桌游叠叠乐:你能玩过它算我输 |《科学》子刊...
  2. pyspark sparksession_PySpark 处理数据和数据建模
  3. opencv获得图片的像素宽度_使用OpenCV实现摄像头测距
  4. 黑苹果 选择语言 点不了_什么是天然的“黑钻”?—科普贴
  5. ANSIBLE--handlers的概念
  6. bash shell是如何识别特殊符号的
  7. SSH软件包:Sftp,scp和ssh-agent
  8. 教你在Ubuntu上体验Mac风格
  9. 关于liaoxuefeng的python3教程实战第四天
  10. activiti7流程设计器_变频空调器通信电路