到你呢?解析应用层协议(三)

到你呢?解析应用层协议

前言

如图,上节聊到Accrptor监听请求后,注册到队列,Poller线程去轮询队列,包装创建SocketProcessor丢到线程池。

在这里插入图片描述

看一下线程池处理以及后续调用具体的方法调用:

处理

源码分析

下面进行源码的分析:

运行SocketProcessorBase的run方法

public final void run() {
    synchronized (socketWrapper) {
        //调用子类SocketProcessor的doRun
        doRun();
    }
}

调用实现类SocketProcessor的doRun

@Override
protected void doRun() {
				。。。。。
    try {
        int handshake = -1;
        try {
            // handshake 是用来处理 https 的握手过程的,
            // 如果是 http 不需要该握手阶段,下面会将该标志设置为 0, 表示握手已经完成
            // 是否已经握手成功
            if (socketWrapper.getSocket().isHandshakeComplete()) {
                handshake = 0;
            } else 
              。。。。
            }
        }
        if (handshake == 0) {
            SocketState state = SocketState.OPEN;
            // Process the request from this socket
            if (event == null) {
                // 默认是读事件处理
                // 这里的getHandler()返回AbstractProtocol.ConnectionHandler,
                // 在Http11NioProtocol对象构造期间被创建并设置到当前NioEndpoint对象
                state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
            } else {
                // 响应指定事件处理
                // 这里的getHandler()返回AbstractProtocol.ConnectionHandler,
                // 在Http11NioProtocol对象构造期间被创建并设置到当前NioEndpoint对象
                state = getHandler().process(socketWrapper, event);
            }
            if (state == SocketState.CLOSED) {
                poller.cancelledKey(getSelectionKey(), socketWrapper);
            }
        }
   。。。。
}

getHandler()拿的是AbstractProtocol内部类ConnectionHandler

public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) {
    。。。。。。
    try {
        if (processor == null) {
        		///协议可能升级
            String negotiatedProtocol = wrapper.getNegotiatedProtocol();
            if (negotiatedProtocol != null && negotiatedProtocol.length() > 0) {
                UpgradeProtocol upgradeProtocol = getProtocol().getNegotiatedProtocol(negotiatedProtocol);
                if (upgradeProtocol != null) {
                    //协议升级如果配置了类UpgradeProtocol
                    processor = upgradeProtocol.getProcessor(wrapper, getProtocol().getAdapter());
                    if (getLog().isDebugEnabled()) {
                        getLog().debug(sm.getString("abstractConnectionHandler.processorCreate", processor));
           。。。。
        }
        if (processor == null) {
            // 从recycledProcessors可循环processors中获取processor
            processor = recycledProcessors.pop();
            if (getLog().isDebugEnabled()) {
                getLog().debug(sm.getString("abstractConnectionHandler.processorPop", processor));
            }
        }
        //创建一个新的Http11Processor
        if (processor == null) {
            processor = getProtocol().createProcessor();
            register(processor);
            if (getLog().isDebugEnabled()) {
                getLog().debug(sm.getString("abstractConnectionHandler.processorCreate", processor));
            }
        }
				,。。。
        do {
        		//循环
            //抽象类AbstractProcessorLight的process方法
            state = processor.process(wrapper, status);
						。。。。。。
             } while ( state == SocketState.UPGRADING);

}

processor.process这里是去处理应用层的小编。

先看一下继承关系。

在这里插入图片描述

Processor类:

所有协议的处理器的通用接口。

AbstractProcessorLight:

这是一个轻量级抽象处理器实现,旨在作为从轻量级升级处理器到 HTTPAJP 处理器的所有处理器实现的基础。

public SocketState process(SocketWrapperBase<?> socketWrapper, SocketEvent status)
        throws IOException {
    //处理不在标准HTTP模式下的正在处理中的请求。
    //目前使用的包括Servlet 3.0异步和HTTP升级连接
    //将来可能会增加更多的用途。这些通常以HTTP请求开始。
    SocketState state = SocketState.CLOSED;
    Iterator<DispatchType> dispatches = null;
    do {
        。。。。
        } else if (status == SocketEvent.OPEN_READ) {
            //可读状态,默认Http11Processor的实现的service
            state = service(socketWrapper);
        } 
      。。。。
    } while (state == SocketState.ASYNC_END ||
            dispatches != null && state != SocketState.CLOSED);

    return state;
}

‼️到了关键的一步,Http11Processor去解析应用层的协议

public SocketState service(SocketWrapperBase<?> socketWrapper)
    throws IOException {
		。。。。。
    // Setting up the I/O
    //初始化输入输出流
    setSocketWrapper(socketWrapper);
		。。。。。
    while (!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null &&
            sendfileState == SendfileState.DONE && !endpoint.isPaused()) {
        // Parsing the request header
        try {
            //解析请求的第一行也就是method、uri以及protocol(GET /S2_3_16_1/hello.action HTTP/1.1),
            // 将相应的值设到request实例中
            if (!inputBuffer.parseRequestLine(keptAlive)) {
                。。。。
            }
            。。。
                //parseHeaders()解析HTTP头将内容(host,ua,connect…)设置到headers实例中
                if (!http09 && !inputBuffer.parseHeaders()) {
              。。。
            }
        } 。。。。
        if (getErrorState().isIoAllowed()) {
         
            try {
                //各种解析请求,组装request
                //通过prepareRequest方法组装request filter,用于处理http消息体
                prepareRequest();
            。。。
        // Process the request in the adapter
        if (getErrorState().isIoAllowed()) {
            try {
                rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
                //获取CoyoteAdapter,调用其service方法
                getAdapter().service(request, response);
        。。。。
     
}

回顾一下整体的方法的调用,最后交给适配器处理,getAdapter().service(request, response)。

在这里插入图片描述

总结

通过这二节内容,我们可以清楚了看到Tomcat如何接收请求,到最后适配转到容器。后面将要讲到适配器处理的细节!!!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340