【tomcat】3、预备知识与参数解析

I/O多路复用与异步I/O本质区别:从epoll到io_uring的演进逻辑 I/O模型是操作系统与应用程序交互的核心机制,涉及阻塞、非阻塞、I/O多路复用和异步I/O四大范式。其底层原理围绕数据拷贝路径、上下文切换开销及事件通知方式展开:传统阻塞I/O受限于线程膨胀,非阻塞需配合事件通知才能实用;I/O多路复用(如epoll)通过内核就绪通知实现单线程高并发管理,属同步语义但支撑异步编程模型;而真正异步I/O(如io_uring)则通过共享内存环形队列、零拷贝提交与完成,消除系统调用与上下文切换,达成数据直通设备。技术价值在于突破C10K/C100K瓶颈,适用于Web服务器、实时交 阅读详情
  • 系列文章目录:https://blog.youkuaiyun.com/hancoder/category_10106944.html
  • 0 sevlet的知识,从上面目录中找
  • 1 tomcat的安装与目录结构:https://blog.youkuaiyun.com/hancoder/article/details/106765035
  • 2 tomcat源码环境搭建: https://blog.youkuaiyun.com/hancoder/article/details/113064325
  • 3 tomcat架构与参数:https://blog.youkuaiyun.com/hancoder/article/details/113065917
  • 4 tomcat源码分析:https://blog.youkuaiyun.com/hancoder/article/details/113062146
  • 5 tomcat调优:https://blog.youkuaiyun.com/hancoder/article/details/113065948

一、socket和http

1 tcp和http

socket是tcp层上面封装的协议,http是应用层封装的协议

计算机网络的知识告诉我们,

  • tcp需要先三次握手后才能通信,udp无需握手。
  • 应用层是软件之间的通信,就是我们说的浏览器和服务器
在这里插入图片描述

流程:

  • TCP连接三次握手。可以把这里认为是socket,但是socket是tcp之上的封装
  • 发送HTTP请求
  • 响应HTTP请求
1.1 TCP

要想明白Socket连接,先要明白TCP连接。手机能够使用联网功能是因为手机底层实现了TCP/IP协议,可以使手机终端通过无线网络建立TCP连接。TCP协议可以对上层网络提供接口,使上层网络数据的传输建立在“无差别”的网络之上。

建立起一个TCP连接需要经过“三次握手”:

  • 第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
  • 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
  • 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。断开连接时服务器和客户端均可以主动发起断开TCP连接的请求,断开过程需要经过“四次握手”(过程就不细写了,就是服务器和客户端交互,最终确定断开)

1.2 HTTP

HTTP协议即超文本传送协议(Hypertext Transfer Protocol ),是Web联网的基础,也是手机联网常用的协议之一,HTTP协议是建立在TCP协议之上的一种应用。作为应用层协议,HTTP是基于TCP/IP协议来传递数据的(HTML文件、图片、查询结果等),HTTP协议不涉及数据包(Packet)传输,主要规定了客户端和服务器之间的通信格式。

HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。

  • 1)在HTTP 1.0中,客户端的每次请求都要求建立一次单独的连接,在处理完本次请求后,就自动释放连接。也就是不支持长连接
  • 2)在HTTP 1.1中,可以在一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求。尽管HTTP1.1开始支持持久连接,但仍无法保证始终连接。而Socket连接一旦建立TCP三次握手,除非一方主动断开,否则连接状态一直保持。

由于HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是一种“短连接”,要保持客户端程序的在线状态,需要不断地向服务器发起连接请求。通常的做法是即时不需要获得任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持连接”的请求,服务器在收到该请求后对客户端进行回复,表明知道客户端“在线”。若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。

一个socket里发送了多个http请求,每个http请求会判断请求头里的connection是否close,是的话处理完关闭socket。

如果是connection:keep-alive,则不会断开。另外tomcat里也有限制同时能同时存在几个活跃的socket,还有一个socket可以处理几个http请求。

对方revcbuff满了就阻塞了

1.3 TCP和HTTP总结
  • HTTP协议:简单对象访问协议,对应于应用层 ,HTTP协议是基于TCP连接的
  • TCP协议: 对应于传输层
  • IP协议: 对应于网络层 TCP/IP是传输层协议,主要解决数据如何在网络中传输;而HTTP是应用层协议,主要解决如何包装数据。
1.4 请求与连接
  • 连接是TCP层面的(传输层),对应socket;
  • 请求是HTTP层面的(应用层),必须依赖于TCP的连接实现;
  • 一个TCP连接中可能传输多个HTTP请求。

2 socket

Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。

  • HTTP连接:http连接就是所谓的短连接,即客户端向服务器端发送一次请求,服务器端响应后连接即会断掉;
  • socket连接:socket连接就是所谓的长连接,理论上客户端和服务器端一旦建立起连接将不会主动断掉;但是由于各种环境因素可能会是连接断开,比如说:服务器端或客户端主机down了,网络故障,或者两者之间长时间没有数据传输,网络防火墙可能会断开该连接以释放网络资源。所以当一个socket连接中没有数据的传输,那么为了维持连接需要发送心跳消息~~具体心跳消息格式是开发者自己定义的
2.1 socket的步骤

一个socket的步骤:

  • serverSocket.bind(addr,backlog)
  • socket = serverSocket.accept()
  • socket.read()
  • socket.write()

在Netty等文章中说了太多回了,我懒得说了,复制点内容吧

socket是”打开—读/写—关闭”模式的实现,以使用TCP协议通讯的socket为例,其交互流程大概是这样子的

  • 服务器根据地址类型(ipv4,ipv6)、socket类型、协议创建socket
  • 服务器为socket绑定ip地址和端口号
  • 服务器socket监听端口号请求,随时准备接收客户端发来的连接,这时候服务器的socket并没有被打开
  • 客户端创建socket
  • 客户端打开socket,根据服务器ip地址和端口号试图连接服务器socket
  • 服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时候socket进入阻塞状态,所谓阻塞即accept()方法一直到客户端返回连接信息后才返回,开始接收下一个客户端谅解请求
  • 客户端连接成功,向服务器发送连接状态信息
  • 服务器accept方法返回,连接成功
  • 客户端向socket写入信息
  • 服务器读取信息
  • 客户端关闭
  • 服务器端关闭
2.2 bind()

看不懂这没关系,我这里是为了解释,只是为了给源码铺垫,后面我会再指引回来

对我而言,我需要注意bind()那个函数,原来在学习中老师都是交绑定一个本地的接口就可以了,但在tomcat源码阅读中,出现了acceptor这个东西,而且还是个数组,据我观察,他就是bind()里的backlog,怎么理解呢?

在查阅手册里,有如下的内容

public void bind(SocketAddress endpoint,//绑定到的IP地址和端口号。 
                 int backlog)//请求进入连接队列的最大长度。

将ServerSocket绑定到特定地址(IP地址和端口号)。 如果地址为null ,则系统将接收临时端口和有效的本地地址来绑定套接字。 

backlog参数是套接字上请求的最大挂起连接数。 其确切语义是实现具体的。 特别地,实现可以施加最大长度,或者可以选择忽略参数altogther。 提供的价值应大于0 。 如果小于或等于0 ,则将使用实现特定的默认值。 

再结合tomcat里acceptor的知识,那么我就总结如下,

  • accept()、read()、write()都是阻塞的
  • accept()后交给BIO的线程池或者NIO的selector,但也得去交啊,如果不去交呢,岂不是只有一个连接在阻塞等待交给selector?另一个线程连阻塞的机会都没有,得在网卡外面等着。
  • 如果指定了backlog参数,就可以认为即使没有提交给后面的selector等read(),但也可以接收多个连接,只是还没提交而已

从我这个想法出发,也就解释了tomcat的最大连接数为什么是 maxConnections+maxAcceptors 两者和的值。

另外tcp握手和这个accept的逻辑前后关系?网上说三次握手后才进入accept队列,但我更认为accept就是3次握手,具体源码应该在linux中看到,先不验证,没大所谓

3 长连接短连接

https://blog.youkuaiyun.com/mccand1234/article/details/91346202

长连接指的是建立了tcp之后可以多次发送http。

长连接:指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接(心跳包),一般需要自己做在线维持。

短连接:是指通信双方有数据交互时,就建立一个TCP连接,数据发送完成后,则断开此TCP连接。

比如Http的,只是连接、请求、关闭,过程时间较短,服务器若是一段时间内没有收到请求即可关闭连接。其实长连接是相对于通常的短连接而说的,也就是长时间保持客户端与服务端的连接状态。

  • 通常的短连接操作步骤是:连接→数据传输→关闭连接;
  • 而长连接通常就是:连接→数据传输→保持连接(心跳)→数据传输→保持连接(心跳)→……→关闭连接;

什么时候用长连接,短连接:

  • 长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况,。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理 速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成Socket错误,而且频繁的Socket创建也是对资源的浪费。

HTTP连接与Socket连接的区别:

  • HTTP是短连接,Socket(基于TCP协议的)是长连接。尽管HTTP1.1开始支持持久连接,但仍无法保证始终连接。而Socket连接一旦建立TCP三次握手,除非一方主动断开,否则连接状态一直保持。
  • HTTP连接服务端无法主动发消息,Socket连接双方请求的发送先后限制。这点就比较重要了,因为它将决定二者分别适合应用在什么场景下。HTTP采用“请求-响应”机制,在客户端还没发送消息给服务端前,服务端无法推送消息给客户端。必须满足客户端发送消息在前,服务端回复在后。Socket连接双方类似peer2peer的关系,一方随时可以向另一方喊话。

二、servlet

servlet三大组件:servlet、filter、listener。

  • servlet:
  • filter:通过filter里的chain.doFilter(request, response);调用servlet,可以实现在前后打印日志
  • listener:监听应用、会话、请求的事件,

我们定义类实现HttpServlet,放到tomcat中,即可拦截到请求。对应的req和resp实例是tomcat创建的

public class MyServlet extends HttpServlet{
    // 重写doGet方法
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp){
        resp.getWriter().println("hhh");
    }
}

三、servlet容器

如下图,浏览器发HTTP请求到服务器后,

  • 如果服务器自己去调用业务类,那么服务器还需要自己调用与实现业务类的逻辑。
  • 如果在把请求交给交给servlet容器,让servlet容器自己去调用业务类,就可以让服务器和业务类解耦

这里的服务器指的是后文的连接器,也就是说服务器应该只负责连接,连接后的结果应该交给servlet容器处理

在这里插入图片描述

如果要把业务类放到servlet容器中,那么它首先得是servlet,那么就设计了servlet接口。接口+容器=servlet规范

而tomcat就是实现了servlet规范,他可以放servlet,他就是一个servlet容器。要实现逻辑,只需要实现servlet然后注册到tomcat等servlet容器即可。

我们的jsp是由dispatchServlet派发过来的,原理还是servlet

servlet容器的工作流程

客户发起请求,http服务器利用连接器把请求获取到,然后把请求交给servlet容器。

连接器把请求先封装为request对象,然后再由适配器封装为servlet request对象,然后就交给servlet容器,就可以调用servlet.service()方法了(会先调用servlet.init())

servlet的知识告诉我们实现service()、doGet()、doPost()等方法都是一个道理。你实现了service()方法就不用父类的service()方法了,你没实现service()方法的话就调用父类的service()方法,父类的service()会调用子类的doGet()、doPost()

另外servlet正常是第一次被访问才创建对象,而在spring中我们是容器初始化后就创建了servlet对象调用了init方法,然后直接可以调用service()

四、NIO等知识

BIO是阻塞的,NIO是非阻塞的,而且可以利用事件机制。

请参考本人博客中其他NIO的知识吧,这里不具体说了,主要继承在netty中。本文只会把tomcat的组件对应到nio的组件上

在使用tomcat时,经常会遇到连接数、线程数之类的配置问题,我们先从NIO方面了解一下,后面再从tomcat的角度了解一下

1 BIO与NIO

BIO的知识告诉我们,因为accept()、read()、write()都是阻塞的方法,造成即使新的连接来了,还是得等当前连接处理完再处理其他连接。然后BIO升级为了线程池版,也就是说read()等业务方法很耗时,那么就可以accept()后把read()逻辑放到线程池里去执行。他的弊端是:

  • 方法都是阻塞的,cpu来回阻塞和唤醒,而且设计用户态和内核态切换,耗时
  • 一个线程只能处理一个连接,因为每个连接都得去线程池里read

NIO的知识告诉我们,连接可以注册到selector上,然后利用事件机制selector.select()获取到哪些连接发送事件需要处理了。这就解决了一个线程可以处理多个连接的问题。

1.2 APR

与NIO更好的是APR(Apache Portable Runtime),是Apache可移植运行库,利用本地库可以实现高可扩展性、高性能;Apr是在Tomcat上运行高并发应用的首选模式,但是需要安装apr、apr-utils、tomcat-native等包。

个人不熟悉,先不讨论

  • BIO是Blocking IO,顾名思义是阻塞的IO;
  • NIO是Non-blocking IO,则是非阻塞的IO。
  • APR是Apache Portable Runtime,是Apache可移植运行库,利用本地库可以实现高可扩展性、高性能;Apr是在Tomcat上运行高并发应用的首选模式,但是需要安装apr、apr-utils、tomcat-native等包。

再多嘴一句,BIO NIO是TCP层之上的协议,不是HTTP协议,他是对socket的封装

2 tomcat中使用的协议

tomcat因为可以注册多个连接器,但是每个连接器都是一种协议protocol。

暂时你先把连接器认为是 接收请求tcp三次握手+形成request 的工具即可。

其中最典型的protocol包括BIO、NIO和APR(Tomcat7中支持这3种,Tomcat8增加了对NIO2的支持,而到了Tomcat8.5和Tomcat9.0,则去掉了对BIO的支持)。

指定tomcat协议

连接器Connector使用哪种protocol,可以通过<connector>元素中的protocol属性进行指定,也可以使用默认值。

对于每个连接器标签<connector>,可以指定是用于处理HTTP的还是AJP请求的,可以处理不同的协议。而HTTP又分为是用哪种通信方式,阻塞还是非阻塞的

  • HTTP/1.1(默认值,使用的协议与Tomcat版本有关)
    • org.apache.coyote.http11.Http11Protocol:BIO(Tomcat7默认)
    • org.apache.coyote.http11.Http11NioProtocol:NIO(Tomcat8默认)
    • org.apache.coyote.http11.Http11Nio2Protocol:NIO2
    • org.apache.coyote.http11.Http11AprProtocol:APR(Tomcat7、8默认,前提是能找到需要的本地库)
  • AJP

五、tomcat参数解析

1 线程数与CPU数

上面NIO的优势在于用几个线程管理很多连接,或者说一个线程selector去进行selector.select()就可以管理至少1024个连接

线程和CPU的关系:

我们知道java可以new很多线程,线程和cpu什么关系?

线程数可以远远大于CPU个数。

比如线程要去进行(等待数据库返回、读写硬盘、读网卡)或者调用了object.wait()等操作,那么就阻塞了。读网卡什么的操作是可以用DMA去准备数据的,DMA准备好数据后,像CPU发起硬件中断,CPU才继续执行该线程,在这期间CPU可以取处理被的线程。所以说,CPU可以处理很多线程

2 acceptCount

在一、2介绍过bind()于accept的关系

accept表示连接等待队列的长度,如果达到该值,请求都不会等待,用户那直接报错connection refused了

当到达最大连接数后,tomcat后将后面的请求存放到任务队列进行排序,任务对垒中排队等待的个数达到acceptCount时,拒绝。

一台tomcat的最大请求数量是 maxConnections+acceptCount

当accept队列中连接的个数达到acceptCount时,队列满,进来的请求一律被拒绝。默认值是100。

accept设置经验

acceptCount的设置,与应用在连接过高情况下希望做出什么反应有关系。如果设置过大,后面进入的请求等待时间会很长;如果设置过小,后面进入的请求立马返回connection refused。

3 maxConnections

Tomcat在任意时刻接收和处理的最大连接数。当Tomcat接收的连接数达到maxConnections时,Acceptor线程不会读取accept队列中的连接;这时accept队列中的线程会一直阻塞着,直到Tomcat接收的连接数小于maxConnections。如果设置为-1,则连接数不受限制。

默认值与连接器使用的协议有关:NIO的默认值是10000,APR/native的默认值是8192,而BIO的默认值为maxThreads(如果配置了Executor,则默认值是Executor的maxThreads)。

在windows下,APR/native的maxConnections值会自动调整为设置值以下最大的1024的整数倍;如设置为2000,则最大值实际是1024。

可以使用ulimit -a查看服务器限制,对于CPU要求更高(计算型)时,不建议配置过大。对于CPU要求不是特别高时,配置建议在2000左右。

3.2 Connections设置经验

另外,BIO的知识告诉我们,最大线程数==最大连接数,因为没有注册事件机制,必须自己去轮询处理。

NIO的最大线程数<<最大连接数

还有,服务器中可以同时接收的连接数为maxConnections+acceptCount

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />

<Connector protocol="AJP/1.3"
           address="::1"
           port="8009"
           redirectPort="8443" />
3.3 查看连接数

假设Tomcat接收http请求的端口是8083,则可以使用如下语句查看连接情况:

# 查看服务器访问数量
netstat -an | grep ESTABLISHED | wc -l  

# 查看端口的连接数
netstat -nat|grep -i "80"|wc -l  
netstat –nat | grep 8083

结果如下所示:

img

可以看出,

  • 有一个连接处于listen状态,监听请求;
  • 还有4个已经建立的连接(ESTABLISHED)
  • 2个等待关闭的连接(CLOSE_WAIT)。
# 查看进程数
ps aux|grep httpd|wc -l  

ps -ef|grep httpd|wc -l 

# 查看Apache的并发请求数及其TCP连接状态: 
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 

  返回结果示例: 
  LAST_ACK 5 
  SYN_RECV 30 
  ESTABLISHED 1597 
  FIN_WAIT1 51 
  FIN_WAIT2 504 
  TIME_WAIT 1057 
  其中的 
  SYN_RECV表示正在等待处理的请求数; 
  ESTABLISHED表示正常数据传输状态; 
  TIME_WAIT表示处理完毕,等待超时结束的请求数。

4 maxThreads

这里指的是处理请求的线程数,前提是已经通过accept()了,是指去线程池里进行read的操作的线程

请求处理线程的最大数量。默认值是200(Tomcat7和8)。如果该Connector绑定了Executor,这个值会被忽略,因为该Connector将使用绑定的Executor,而不是内置的线程池来执行任务。

Threads设置经验

ps命令可以查看进程状态,如执行如下命令:

ps –e | grep java

结果如下图:

img

可以看到,只打印了一个进程的信息;27989是进程id,java是指执行的java命令。这是因为启动一个tomcat,内部所有的工作都在这一个进程里完成,包括主线程、垃圾回收线程、Acceptor线程、请求处理线程等等。

通过如下命令,可以看到该进程内有多少个线程;其中,nlwp含义是number of light-weight process

ps –o nlwp 27989
# 输出
NLWP
73

img

可以看到,该进程内部有73个线程;但是73并没有排除处于idle状态的线程。要想获得真正在running的线程数量,可以通过以下语句完成:

ps -eLo pid ,stat | grep 27989 | grep running | wc -l

其中ps -eLo pid ,stat可以找出所有线程,并打印其所在的进程号和线程当前的状态;两个grep命令分别筛选进程号和线程状态;wc统计个数。其中,ps -eLo pid ,stat | grep 27989输出的结果如下:

img

图中只截图了部分结果;Sl表示大多数线程都处于空闲状态。

5 其他参数

这个部分的内容可以跳过

  • KeepAlive:KeepAlive是在HTTP1.1中定义的,用来保持客户机和服务器的长连接,通过减少建立TCP Session的次数来提高性能。常用的配置参数有{KeepAlive, KeepAliveTimeout, MaxKeepAliveRequests}。
  • KeepAliveTimeout:决定一个KeepAlive的连接能保持多少时间,Timeout就尽快shutdown链接,若还有数据必须再建立新的连接了;其实是read()阻塞时间。长连接就是读完最后一次请求的20s后关闭socket
  • MaxKeepAliveRequests:服务多少个请求就shutdown关闭socket连接。
  • maxThreads:tomcat起动的最大线程数,即同时处理的任务个数,默认值为200
    • 一个socket连接对应一个线程,而一个socket可以接收多个http请求,但是线程数决定了同时处理http请求的数量
    • 每一次HTTP请求到达Web服务,tomcat都会创建一个线程来处理该请求,那么最大线程数决定了Web服务容器可以**同时处理多少个请求**。maxThreads默认200,肯定建议增加。但是,增加线程是有成本的,更多的线程,不仅仅会带来更多的线程上下文切换成本,而且意味着带来更多的内存消耗。JVM中默认情况下在创建新线程时会分配大小为1M的线程栈,所以,更多的线程异味着需要更多的内存。线程数的经验值为:1核2g内存为200,线程数经验值200;4核8g内存,线程数经验值800。
  • maxConnections:tomcat能够接受的最大连接数,maxConnections 默认值是10000。但是还有个参数acceptCount可以决定连接数的大小
    • 对于Java的阻塞式BIO,默认值是maxthreads的值;如果在BIO模式使用定制的Executor执行器,默认值将是执行器中maxthreads的值。
    • 对于Java 新的NIO模式,一个线程可以同时处理多个连接。
    • 对于windows上APR/native IO模式,maxConnections默认值为8192,这是出于性能原因,如果配置的值不是1024的倍数,maxConnections 的实际值将减少到1024的最大倍数。
    • 如果设置为-1,则禁用maxconnections功能,表示不限制tomcat容器的连接数。
    • maxConnections和accept-count的关系为:当连接数达到最大值maxConnections后,系统会继续接收连接,但不会超过acceptCount的值。
  • acceptCount:当tomcat起动的线程数达到最大时,接受排队的请求个数,默认值为100
    • 情况1:接受一个请求,此时tomcat起动的线程数没有到达maxThreads,tomcat会起动一个线程来处理此请求。
      情况2:接受一个请求,此时tomcat起动的线程数已经到达maxThreads,tomcat会把此请求放入等待队列,等待空闲线程。
      情况3:接受一个请求,此时tomcat起动的线程数已经到达maxThreads,等待队列中的请求个数也达到了acceptCount,此时tomcat会直接拒绝此次请求,返回connection refused
    • 原来tomcat最大连接数取决于maxConnections这个值加上acceptCount这个值,在连接数达到了maxConenctions之后,tomcat仍会保持住连接,但是不处理,等待其它请求处理完毕之后才会处理这个请求。
图解:maxConnections、maxThreads、acceptCount关系

https://blog.youkuaiyun.com/quliuwuyiz/article/details/79979031

用一个形象的比喻,通俗易懂的解释一下tomcat的最大线程数(maxThreads)、最大等待数(acceptCount)和最大连接数(maxConnections)三者之间的关系。

我们可以把tomcat比做一个火锅店,流程是取号、入座、叫服务员,可以做一下三个形象的类比:

(1)acceptCount 最大等待数
可以类比为火锅店的排号处能够容纳排号的最大数量;排号的数量不是无限制的,火锅店的排号到了一定数据量之后,服务往往会说:已经客满。
(2)maxConnections 最大连接数
可以类比为火锅店的大堂的餐桌数量,也就是可以就餐的桌数。如果所有的桌子都已经坐满,则表示餐厅已满,已经达到了服务的数量上线,不能再有顾客进入餐厅了。
(3)maxThreads:最大线程数
可以类比为厨师的个数。每一个厨师,在同一时刻,只能给一张餐桌炒菜,就像极了JVM中的一条线程。

整个就餐的流程,大致如下:
  • (1)取号:如果maxConnections连接数没有满,就不需要取号,因为还有空余的餐桌,直接被大堂服务员领上餐桌,点菜就餐即可。如果 maxConnections 连接数满了,但是取号人数没有达到 acceptCount,则取号成功。如果取号人数已达到acceptCount,则拿号失败,会得到Tomcat的Connection refused connect 的回复信息。
  • (2)上桌:如果有餐桌空出来了,表示maxConnections连接数没有满,排队的人,可以进入大堂上桌就餐。
  • (3)就餐:就餐需要厨师炒菜。厨师的数量,比顾客的数量,肯定会少一些。一个厨师一定需要给多张餐桌炒菜,如果就餐的人越多,厨师也会忙不过来。这时候就可以增加厨师,一增加到上限maxThreads的值,如果还是不够,只能是拖慢每一张餐桌的上菜速度,这种情况,就是大家常见的“上一道菜吃光了,下一道菜还没有上”尴尬场景。

maxConnections、maxThreads、acceptCount关系图如下

在这里插入图片描述

五、tomcat的层次

相信别的文章里介绍过N回tomcat的层次了,死记硬背还是不懂,那我就反向操作从xml的角度说吧

Tomcat 服务器的配置主要集中于 tomcat/conf 下的 catalina.policy、catalina.properties、context.xml、server.xml、tomcat-users.xml、web.xml 文件。

这里写图片描述

1 server

对应Server组件,逻辑上表示整个Tomcat,即整个Catalina Servlet容器。它处于Tomcat顶层,可以包含一个或多个Service层。Tomcat提供了该层接口的一个默认实现,所以通常不需要用户自己去实现。

server.xml 是tomcat 服务器的核心配置文件,包含了Tomcat的 Servlet 容器(Catalina)的所有配置。由于配置的属性特别多,我们在这里主要讲解其中的一部分重要配置。

tomcat是一个servlet容器,同时他是一个server,全局唯一

Server是server.xml的根元素,用于创建一个Server实例,默认使用的实现类是org.apache.catalina.core.StandardServer

<Server port="8005" shutdown="SHUTDOWN">
    ...
</Server>

可选参数:

  • port : Tomcat 监听的关闭服务器的端口。
  • shutdown: 关闭服务器的指令字符串,调优的时候要关闭他。

Server内嵌的子元素为 Listener、GlobalNamingResources、Service。

对于监听器:默认配置的5个Listener ,实现了LifecycleListener接口,是server的监听器

<!-- 用于以日志形式输出服务器 、操作系统、JVM的版本信息-->
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />

<!-- 用于加载(服务器启动) 和 销毁 (服务器停止) APR。 如果找不到APR库, 则会输出日志, 并不影响Tomcat启动 ‐‐>
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />

<!-- 用于避免JRE内存泄漏问题 -->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />

<!-- 用户加载(服务器启动) 和 销毁(服务器停止) 全局命名服务 -->
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

<!-- 用于在Context停止时重建Executor 池中的线程, 以避免ThreadLocal 相关的内存泄漏 -->
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

GlobalNamingResources 中定义了全局命名服务:

<!-- Global JNDI resources
Documentation at /docs/jndi‐resources‐howto.html
-->
<GlobalNamingResources>
    <!-- Editable user database that can also be used by UserDatabaseRealm to authenticate users
-->
    <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat‐users.xml" />
</GlobalNamingResources>

2 Service

对应Service组件,是包含在Server层中的一个逻辑功能层。它包含一个Engine层,以及一个或多个连接器(Connector)。

service==多个连接器+一个servlet容器

Service组件将一个或多个Connector组件绑定到Engine层上,Connector组件侦听端口,获得用户请求,并将请求交给Engine层处理,同时把处理结果发给用户,从而实现一个特定的实际功能。Tomcat提供了Service接口的默认实现,所以通常也不需要用户定制。

一个Server服务器,可以包含多个Service服务。

该元素用于创建 Service 实例,默认使用 org.apache.catalina.core.StandardService。默认情况下,Tomcat 仅指定了Service 的名称, 值为 “Catalina”。Service 可以内嵌的子元素为 :Listener、Executor、Connector、Engine,其中 :

  • Listener 用于为Service添加生命周期监听器,
  • Executor用于配置Service 共享线程池,如果连接器没有指定自己的线程池,将使用这个线程池
  • Connector 用于配置Service 包含的链接器,
  • Engine 用于配置Service中链接器对应的Servlet 容器引擎。
<Service name="Catalina">
    ...
</Service>

3 Connector

Connector 用于创建链接器实例。默认情况下,server.xml 配置了两个链接器,

  • 一个支持HTTP协议,
  • 一个支持AJP协议。

因此大多数情况下,我们并不需要新增链接器配置,只是根据需要对已有链接器进行优化。

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />

<Connector protocol="AJP/1.3"
           address="::1"
           port="8009"
           redirectPort="8443" />
----------------------------------------
可以配置的参数参考如下
<Connector port="8080"
           protocol="HTTP/1.1"
           executor="tomcatThreadPool" 
           maxThreads="1000"
           minSpareThreads="100" 
           acceptCount="1000" 
           maxConnections="1000" 
           connectionTimeout="20000"
           compression="on" 
           compressionMinSize="2048" 
           disableUploadTimeout="true"
           redirectPort="8443"
           URIEncoding="UTF‐8" />

属性说明:

  • port: 端口号,Connector 用于创建服务端Socket 并进行监听, 以等待客户端请求链接。如果该属性设置为0,Tomcat将会随机选择一个可用的端口号给当前Connector使用。

  • executor:本连接器使用的线程池,指向<executor>标签的引用name

  • protocol : 当前Connector 支持的访问协议。 默认为 HTTP/1.1, 并采用自动切换机制选择一个基于 JAVA NIO的链接器或者基于本地APR的链接器(根据本地是否含有Tomcat的本地库判定)。

    • 如果不希望采用上述自动切换的机制, 而是明确指定协议, 可以使用以下值。

    • // 对于Http协议:
      org.apache.coyote.http11.Http11NioProtocol // 非阻塞式 Java NIO 链接器 
      org.apache.coyote.http11.Http11Nio2Protocol // 非阻塞式 JAVA NIO2 链接器
      org.apache.coyote.http11.Http11AprProtocol  // APR 链接器
      
      <Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
                 connectionTimeout="20000"
                 redirectPort="8443" />
      ------------------
      // 对于AJP协议 
      
      org.apache.coyote.ajp.AjpNioProtocol  // 非阻塞式 Java NIO 链接器 
      org.apache.coyote.ajp.AjpNio2Protocol //非阻塞式 JAVA NIO2 链接器
      org.apache.coyote.ajp.AjpAprProtocol  //APR 链接器
      
  • connectionTimeOut : Connector 接收链接后的等待超时时间, 单位为 毫秒。 -1 表示不超时。

  • redirectPort:接收到一个请求,当前Connector 不支持SSL请求, 接收到了一个请求, 并且也符合security-constraint 约束, 需要SSL传输,Catalina自动将请求重定向到指定的端口。

  • executor: 指定共享线程池的名称, 也可以通过maxThreads、minSpareThreads等属性配置内部线程池。

  • URIEncoding : 用于指定编码URI的字符编码, Tomcat8.x版本默认的编码为 UTF-8 ,

    • Tomcat7.x版本默认为ISO-8859-1。
3.2 Executor

线程池在service中没有executor标签的话就使用的默认的线程池,多个连接器共享一个线程池。

默认情况下,Service 并未添加共享线程池配置。 如果我们想添加一个线程池, 可以在下添加如下配置:

<!--在service标签中配置线程池-->
<Executor name="tomcatThreadPool" 
          namePrefix="catalina‐exec‐" 
          maxThreads="200" 
          minSpareThreads="100"
          maxIdleTime="60000"
          maxQueueSize="Integer.MAX_VALUE" 
          prestartminSpareThreads="false"
          threadPriority="5"
          className="org.apache.catalina.core.StandardThreadExecutor"/>
然后在下面的connector标签中指定

jconsole工具,找到本地线程的bootstrap,可以在线程里看到http-nio-exec-ID ajp-nio-exec-ID线程(原有的)。如果我们自己命名了<Executor name,那么就能看到我们自己的name-exec-线程id

然后我们在下面的connector标签中配置好后,再查看的话会发现比如nio-exec的名字变了

属性含义
name线程池名称,用于 Connector中指定。
namePrefix所创建的每个线程的名称前缀,一个单独的线程名称为 namePrefix+threadNumber。
maxThreads池中最大线程数。
minSpareThreads活跃线程数,也就是核心池线程数,这些线程不会被销毁,会一直存在。
maxIdleTime线程空闲时间,超过该时间后,空闲线程会被销毁,默认值为6000(1分钟),单位毫秒。
maxQueueSize在被执行前最大线程排队数目,默认为Int的最大值,也就是广义的无限。除非特殊情况,这个值不需要更改,否则会有请求不会被处理的情况发生。
prestartminSpareThreads启动线程池时是否启动 minSpareThreads部分线程。默认值为false,即不启动。
threadPriority线程池中线程优先级,默认值为5,值从1到10。
className线程池实现类,未指定情况下,默认实现类为 org.apache.catalina.core.StandardThreadExecutor。如果想使用自定义线程池首先需要实现 org.apache.catalina.Executor接口。

如果不配置共享线程池,那么Catalina 各组件在用到线程池时会独立创建。

4 container四大容器

这里写图片描述

4.0 管道

你可能听说过了tomcat有4大容器,而且每个容器有自己的管道。我把四大容器称为EHCW,他们是==父子容器==的关系。

Tomcat里还有个组件pipeline,他有个list属性walve阀门。walve实现类有

实现类为:

  • StandardEngineValve、
  • StandardHostValve、
  • StandardContextValve、
  • StandardWrapperValve。

可以实现RequestFilterWalve接口自定义阀门。可以记录日志

Container处理请求是使用Pipeline-Valve管道来处理的!(Valve是阀门之意,通过这个阀门后才进入下一个阀门)

Pipeline-Valve是责任链模式,责任链模式是指在一个请求处理的过程中有很多处理者依次对请求进行处理,每个处理者负责做自己相应的处理,处理完之后,在函数体的最后一句交给下一个处理着继续处理。(转入下一个pipeline处理)

这里写图片描述

在源码中体现为,

请求来了之后new Request,request.setHost,req.setContext,req.setWarpper,


// service的getPipeline().getFirst().invoke()方法
connector.getService().getContainer().getPipeline().getFirst().invoke();

// 在invoke()里最后一句又调用host的方法
host.getPipeline().getFirst().invoke();

// 在他的最后一句又调用context的方法
context.getPipeline().getFirst().invoke();

// 在invoke()里最后一句又调用wrapper的方法
wrapper.getPipeline().getFirst().invoke();

// 然后在wrapper里行过滤链FilterChain,在过滤链的doFilter()里追踪到`Servlet`的`service()`方法
wrapper.allocate()得到servlet,

4.1 Engine

对应Engine组件,该层是请求分发处理层,可以连接多个Connector。它从Connector接收请求后,解析出可以完成用户请求的URL,根据该URL可以把请求匹配到正确的Host上,当Host处理完用户请求后,Engine层把结果返回给适合的连接器,再由连接器传输给用户。该层的接口一般不需要用户来定制,特殊情况下,用户可以通过实现该接口来提供自定义的引擎。

实现类StandardEngine

Engine 作为Servlet 引擎的顶级元素,内部可以嵌入: Cluster、Listener、Realm、Valve和Host。

<Engine name="Catalina"
        defaultHost="localhost">
    ...
</Engine>
  • name
  • defaultHost:默认的host。主机输入localhost的时候默认找的host

engine有四大组件:

  • Cluster: (很少使用)实现tomcat集群,例如session共享等功能,通过配置server.xml可以实现,对其包含的所有host里的应用有效,该模块是可选的。其实现方式是基于pipeline+valve模式的,
    • 在调优的文章里我们会看到他可以解决session共享问题,原理是复制,明显不好,所以很少用
  • Realm: 实现用户权限管理模块,例如用户登录,访问控制等,通过通过配置server.xml可以实现,对其包含的所有host里的应用有效,该模块是可选的;
  • Pipeline: 每个容器对象都有一个pipeline,它不是通过server.xml配置产生的,是必须有的。它就是容器对象实现逻辑操作的骨架,在pipeline上配置不同的valve,当需要调用此容器实现逻辑时,就会按照顺序将此pipeline上的所有valve调用一遍,这里可以参考责任链模式;
  • Valve: 实现具体业务逻辑单元。可以定制化valve(实现特定接口),然后配置在server.xml里。对其包含的所有host里的应用有效。定制化的valve是可选的,但是每个容器有一个缺省的valve,例如engine的StandardEngineValve,是在StandardEngine里自带的,它主要实现了对其子host对象的StandardHostValve的调用,以此类推。
4.2 Host

对应Host组件,该层表示一个虚拟主机,一个Engine层可以包含多个Host层,每个Host层可以包含一个或多个Context层,对应不同的Web应用。因为Tomcat给出的Host接口的实现(类StandardHost)提供了重要的附加功能,所以用户通常不需要定制Host。

实现类StandardHost

每个host对应一个webapps目录,记住是webapps,不是下面的项目。因为tomcat里原来只配置了一个localhost,所以可以理解为host就是webapps,而context是我们的项目应用。

Host 元素用于配置一个虚拟主机, 它支持以下嵌入元素:Alias、Cluster、Listener、Valve、Realm、Context。如果在Engine下配置Realm, 那么此配置将在当前Engine下的所有Host中共享。 同样,如果在Host中配置Realm , 则在当前Host下的所有Context中共享。Context中的Realm优先级 >Host 的Realm优先级 >Engine中的Realm优先级。

<Host name="localhost"
      appBase="webapps"
      unpackWARs="true"
      autoDeploy="true">
    ...
</Host>

属性说明:

  • 1) name: 当前Host通用的网络名称, 必须与DNS服务器上的注册信息一致。 Engine中包含的Host必须存在一个名称与Engine的defaultHost设置一致。
  • 2) appBase: 当前Host的应用基础目录, 当前Host上部署的Web应用均在该目录下(可以是绝对目录,相对路径)。默认为webapps。这个选项对我们理解很重要
  • 3) unpackWARs: 设置为true, Host在启动时会将appBase目录下war包解压为目录。设置为false, Host将直接从war文件启动。
  • 4) autoDeploy: 控制tomcat是否在运行时定期检测并自动部署新增或变更的web应用。热部署

怎么理解host,难道我们一台主机还能有多个ip?的确可以,一方面我们可以安装多个网卡设置多个ip,另一方面可以修改/etc/hosts文件,让不同的域名解析DNS都映射到本机的ip,这叫虚拟主机。下面我们假设增加一个host标签

通过给Host添加别名,我们可以实现同一个Host拥有多个网络名称,配置如下:

<Host name="www.AAA.com"
      appBase="webapps"
      unpackWARs="true"
      autoDeploy="true">
    <Alias>www.web2.com</Alias>
</Host>

我们就可以通过www.AAA.com访问那个host了,而不只是localhost

这个时候,我们就可以通过两个域名访问当前Host下的应用(需要确保DNS或hosts中添加了域名的映射配置)。

浏览器请求–>去etc/hosts下进行域名解析,拿到你自己配置的,转到tomcat里

这样就实现了虚拟主机,虽然www.aaa.com 和www.bbb.com不同,但都转到了tomcat下

4.3 Context

对应Context组件,该层代表某个虚拟主机上的实际目录或一个WAR,即单个Web应用程序,它运行在特定的虚拟主机中,使用最为频繁。一个Host层包含多个Context层,每一个Context都有唯一的路径,Host层接到请求后,根据用户请求的URL,将请求定位到Context层。

部署应用的方式:war,文件夹,server.xml,conf。war包解压后就是文件夹,文件夹下必须有WEB-INF/子文件夹,WEB-INF/classes存放class,servlet可以放到这里。类上注解@WebServlet可以指定拦截地址。所以我们得去找dispatcherServlet类。tomcat中有实现类StandardContext

  • 描述符的方式可以指定不放在webapps下的文件夹
  • 配置文件里有unpackWARs属性指定默认解压war包
  • Jar包里只有class文件,需要我们配置其他目录
  • War那个会负责遍历.war结尾的文件,不会管.jar

我们在webapps下可以看到root、examples等目录,这些都是项目,root是指如果只是知道了www主机名,没有指定要访问哪个项目,默认访问的就是那个下面,比如www.baidu.com ,只是指定了host,没有指定context,那么访问的就是root那个项目。

Context 用于配置一个Web应用,默认的配置如下:

<Context docBase="myApp"
        path="/App">
   ....
</Context>

属性描述:

  • 1) docBase:Web应用目录或者War包的部署物理路径。可以是绝对路径,也可以是相对于 Host appBase的相对路径。
  • 2) path:Web应用的Context 访问路径。如果我们Host名为localhost, 则该web应用访问的根路径为: http://localhost:8080/App。

它支持的内嵌元素为:CookieProcessor, Loader, Manager,Realm,Resources,WatchedResource,JarScanner,Valve。

<Host name="www.tomcat.com"	appBase="webapps" unpackWARs="true"
      autoDeploy="true">
    <Context docBase="D:\servlet_project03" path="/myApp"></Context>
    <Valve className="org.apache.catalina.valves.AccessLogValve"
           directory="logs"
           prefix="localhost_access_log" 
           suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host>
4.4 Servlet

Wrapper:Wrapper是context下面的,httpServlet实现类只有一个实例,共用的话请求过来都调用同一个,会并发不安全。为了解决安全,可以实现singleThreadModel接口,单线程模型,此时每个请求都是一个实例。tomcat最多20实例。多出来的请求阻塞。重用会重新初始化。tomcat中有实现类StandardWrapper

  • 同一个context下可能有多个类型servlet实例,所以要用wrapper对servlet分类

5 tomcat-users.xml

该配置文件中,主要配置的是Tomcat的用户,角色等信息,用来控制Tomcat中manager, host-manager的访问权限。

(七) Tomcat 源码系列之 Jsp 处理流程 接着昨天讲的, Tomcat 是如何响应的, 也就是如何请求转发和重定向的? 聊这个之前,先来看看 Tomcat 是如何处理 jsp 页面的? 查看 /conf/web.xml 配置文件 <web-app .... > <servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.Defau 阅读详情

相关推荐

【无标题】

可以看到这是一个带过滤的rce,并且还需要绕过空格,通过·查询资料得到了${IFS},$IFS$9,<,$IFS。然后f,l,a,g都被过滤了,可以用中括号[]来进行正则匹配,把GET传的参数改为?cmd=uniq /[e-h][k-n][^-b][e-h],就得到了flag。cmd={%0A"cmd":"/bin/cat /home/rceservice/flag"%0A}可以看到l被过滤了ls用不了了可以用dir用GET传参cmd=dir /,POST传参shell=system。

2501_94507425的博客 303

Tomcat 原理浅析

web 概念 资源的分类: 静态资源:所有用户访问后,得到的结果都是一样的。静态资源可以直接被浏览器解析(html、css、js)。 动态资源:每个用户访问相同的资源后,得到的结果可能是不一样的。动态资源被访问后, 需要先转换为静态资源,再返回给浏览器解析(servlet/jsp、php、asp)。 网络通信三要素: IP:电子设备在网络中的唯一标识 端口:应用程序在计算机中的唯一标识 传输协议:规定数据的传输规则 web 服务器软件:webLogic(oracle 公司)、webSphere(

戏流年的博客 752

Xarray实战:从气象数据到可视化分析的完整流程(附Python代码)

本文详细介绍了使用Xarray库处理气象数据的完整实战流程。针对气象领域常见的NetCDF和GRIB格式,文章从数据读取、坐标操作、智能索引、统计计算到高级可视化,提供了完整的Python代码示例。重点阐述了Xarray如何高效处理高维标记数据,帮助地球科学领域的研究人员将繁琐的数据处理工作转化为高效的分析流水线。

d6e7f8g9h的博客 290

(三)Tomcat源码解析 - Tomcat基础知识介绍

一、Tomcat目录结构 1、bin: 存放启动和关闭tomcat脚本 Catalina:主要的脚本,用以启动和停止服务,供其他脚本调用。 Cpappent:其他脚本调用该脚本在Tomcat启动前动态设置classpath,允许用户在同一个安装下通过设置配置文件来重写该配置参数,各用户之间的设置互不影响。 Digest:该脚本用于创建同期管理验证的摘要密码,通过加密密码提高安全性,

AnndyR的专栏 685

Arduino智能小灯DIY:人体感应+光线感应+蓝牙控制全攻略(附完整代码)

本文提供了一份完整的Arduino智能小灯DIY制作指南。项目融合了人体感应、光线感应与蓝牙控制三大功能,通过详细的硬件清单、电路连接图、核心逻辑讲解及附带的完整代码,手把手教你打造一个能自动感知环境与人、并支持手机远程控制的智能照明装置,是入门智能家居和物联网开发的绝佳实践。

java5的博客 1094

点云体素化算法研究-3.Voxelization 三维模型体素化

体素(voxel)即体积元素的简称,是数字数据在三维空间分割上的最小的单位。体素化就是通过创建三维体素网格来表示三维物体,是一种将无序点云变为有序点云的降采样的空间数据结构方法,便于实现点云的空间卷积。激光雷达(LiDAR)| Open3D:第五节 表面重建-体素化。

周陽讀書 2067

【Web开发】——tomcat安装和介绍

介绍了http的服务器tomcat,手把手教你从安装到发布一个网页.介绍了如果启动服务器,将一个html页面部署到服务器上,将一个文件夹部署在服务器上

weixin_51574797的博客 407

跨模态行人重识别实战:Python复现SYSU-MM01官方评估协议

本文详细介绍了如何用Python复现SYSU-MM01数据集的官方评估协议,以解决原Matlab代码在Python生态中不便使用的问题。文章深入解析了数据集的`indoor`与`all`两种评估模式,并提供了完整的Python代码实现,包括特征加载、相似度计算、Rank-k与mAP指标计算等核心步骤,确保评估结果与官方Matlab版本完全一致,助力跨模态行人重识别研究。

weixin_29081163的博客 99

Tomcat简介及其配置文件解析

简介 Apache软件基金会(也就是Apache Software Foundation,简称为ASF),是专门为支持开源软件项目而办的一个非盈利性组织。Tomcat是Apache 软件基金会的Jakarta 项目(开放源代码开发项目)中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat ...

qq_43686584的博客 1156

YOLOv11涨点改进| SCI一区2026 |独家创新首发、特征融合改进篇|引入FAFM特征对齐融合模块,通过特征对齐和融合两个阶段,助力多模态融合小目标检测,小目标检测,SAR图像目标检测高效涨点

🔥本文提出了一种改进YOLOv11网络模型的方法,通过引入FAFM(特征对齐融合模块)来解决多模态目标检测中的特征空间错位问题。FAFM模块采用可变形卷积和内容引导注意力机制,有效实现了跨模态特征对齐与融合,充分利用了不同模态间的互补信息。该方法在保持模型轻量化的同时,显著提升了目标检测精度和鲁棒性,特别是在复杂背景和模态差异较大的场景下表现突出。文章详细介绍了FAFM模块的结构、原理、优势,并提供了完整的代码实现和模型配置方案,为多模态目标检测任务提供了实用的技术参考。

Ai缝合怪、助力小伙伴高效发论文 268

别再无脑调打码平台了!聊聊 ddddocr 在爬虫验证码识别中的真实边界

ddddocr是国产开源社区的优秀成果,它大幅降低了验证码识别的入门门槛。工具的自由不等于工程的自由。真正的能力不在于“会不会调库”,而在于能否准确判断工具的适用边界、构建鲁棒的容错机制、并在成本与效果之间做出理性权衡。下次当你准备在爬虫中加入验证码识别时,不妨先问自己:这个站点的验证码类型是否在ddddocr的能力圈内?我的预处理是否针对该站点做过专项调试?我的失败重试和监控机制是否完备?如果三个问题都能肯定回答,那么ddddocr就是你的利器;如果有任何一个犹豫,请先补齐短板再上路。评论区交流:你用。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1281

从零开始写一个迷你版的Tomcat

点击上方蓝色“程序猿DD”,选择“设为星标”回复“资源”获取独家整理的学习资料!来源 |www.jianshu.com/p/dce1ee01fb90Tomcat,这只3脚猫,大学的时...

程序猿DD 1071

基于Simulink的无线充电系统LCC补偿网络建模与控制

本文详细介绍了基于Simulink的无线充电系统LCC补偿网络建模与控制方法。首先分析了LCC补偿网络的恒流输出、软开关实现和抗偏移能力等优势,并对比了不同补偿拓扑特性。随后分步骤讲解了Simulink建模流程,包括LCC主电路构建、关键参数设计、双闭环控制系统实现等核心环节。重点阐述了移相控制策略和软开关验证方法,提供了系统效率计算和抗偏移测试的调试技巧。最后展示了仿真结果,在耦合系数变化20%时,闭环系统仍能保持输出电压稳定在±2%波动范围内。文章还探讨了工程扩展方向,并针对常见问题给出了解决方案,为无

xiaoheshang_123的博客 539

Java 性能 08 - Tomcat 线程池优化(maxThreads/minSpareThreads)

摘要:Tomcat线程池中的maxThreads和minSpareThreads是高并发Web应用的关键性能参数。maxThreads限制最大线程数(默认200),防止资源耗尽;minSpareThreads保持最小空闲线程(默认10),减少创建开销。优化建议: CPU密集型:maxThreads接近核心数 I/O密集型:可设较高(200-500) 提升minSpareThreads(如50)预热线程,减少延迟 测试显示平衡配置(max=200, min=50)比低配响应快30%,比高配更节省资源。需结合业

千淘万漉虽辛苦,吹尽狂沙始到金 2万+

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

java中文问题详解

我来说一下tomcat如何实现JSP的你就明白了。预备知识: 1.字节和unicode  Java内核是unicode的,就连class文件也是,但是很多媒体,包括文件/流的保存方式  是使用字节流的。 因此Java要对这些字节流经行转化。char是unicode的,而byte是字节.  Java中byte/char互转的函数在sun.io的包中间有。其中ByteToCharConverter类是

kunmengzi的专栏 436

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

别再手动折腾了!用Docker Compose一键部署Jira 9.12.0,5分钟搞定开发测试环境

本文详细介绍了如何使用Docker Compose一键部署Jira 9.12.0,5分钟内快速搭建开发测试环境。通过容器化技术,简化了传统手动配置的复杂流程,大幅提升部署效率,特别适合敏捷开发团队。文章包含完整的docker-compose.yml配置、性能调优技巧和常见问题解决方案。

476

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

高龄白菜JAVA学习第三十五天(Tomcat|Servlet)

1.什么是servlet

mangosea的博客 163

tomcat访问所有的资源,都是用Servlet来实现的

感谢大佬:https://www.zhihu.com/question/57400909 tomcat访问所有的资源,都是用Servlet来实现的。 在Tomcat看来,资源分3种 静态资源,如css,html,js,jpg,png等 2. Servlet 3. JSP 对于静态资源,Tomcat最后会交由一个叫做DefaultServlet的类来处理 对于Servlet ,...

Jason的学习笔记 579

tomcat大量time wait问题

在服务端访问量大的时候检测到大量的time wait,并且接口请求延时较高。 执行 netstat -n |awk ‘/^tcp/{++S[$NF]}END{for(m in S) print m,S[m]}’ 这个shell命令的意思是把netstat -n 后结果的最后一条放到S[]数组中,如果相同则执行+1操作。 此时能看到TCP各种状态下的连接数量,示例 服务端架构是采用nginx

today的专栏 1万+

详解tomcat的连接数与线程池

前言 在使用tomcat时,经常会遇到连接数、线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector)。 在前面的文章详解Tomcat配置文件server.xml中写到过:Connector的主要功能,是接收连接请求,创建Request和Response对象用于和请求端交换数据;然后分配线程让Engine(也就是Servlet容器)来处理这个请求,并把产生的Request和Response对象传给Engine。当Engine处理完请求后,也会通过Connecto..

shenxian251的博客 566

TOMCAT原理

一、TOMCAT的基本架构 二、Coyote连接器 三、Catalina容器 四、启动流程介绍 五、请求处理流程介绍 六、Jasper引擎 七、服务器配置 1、Server、Service 2、Executor 3、Connector 4、Engine、Host 5、Context ...

liming0025的专栏 5490

学习Tomcat这一篇就够了

Tomcat 第一章 Tomcat概述 1.1、Tomcat概述 Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,Tomcat 5支持最新的Servlet 2.4 和JSP 2.0 规范。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并

轻松的小希 11万+

Tomcat工作原理详细介绍

大部分企业的 Web 应用都运行在它上面,Tomcat 对于程序员来说算是老朋友了,那么今天带大家走近这位老朋友,看看它是如何处理 Web 请求,以及它内部的体系结构,这对帮助我们理解 Tomcat 的使用大有益处。本文你将会学会如下内容:Web 容器与 TomcatTomcat 连接器Tomcat 容器要说清楚 Tomcat 做的事情先要从早期的 Web 应用说起。图 1:浏览器通过 HTTP 服务器获取静态资源如图 1 所示,最开始用户通过浏览器查看诸如新闻之类的静态资源,此时就需要通过 HTTP 服务

Java搜索工程技术栈 6216

Tomcat工作原理介绍

从工作原理方面来认识学习Tomcat

qiaotl的博客 2228

Tomcat工作原理详解

Tomcat简介   作者:杨晓(http://blog.sina.com.cn/u/1237288325) 一、Tomcat背景   自从JSP发布之后,推出了各式各样的JSP引擎。Apache Group在完成GNUJSP1.0的开发以后,开始考虑在SUN的JSWDK基础上开发一个可以直接提供Web服务的JSP服务器,当然同时也支持Servlet, 这样Tomcat就诞生了。Tomc

res_cue的专栏 11万+

tomcat工作原理(基本过程)

tomcat工作原理铺垫知识tomcat工作原理tomcat工作流程图 今天嘞,我们来粗略的谈一下tomcat的工作原理,希望有错误的地方请大家积极指出! 铺垫知识 emmm,在说之前我先说一下基本的铺垫知识吧。 tomcat是使用java语言编写的 计算机依靠网卡设备和外界交互,网卡将电信号转变为物理信号(0,1),网卡在数据转化完毕之后将数据交给端口 一台电脑最多可以开216个端口,不会出现...

qq_43677686的博客 5322
上一篇: 【tomcat】2、源码环境搭建
下一篇: 【tomcat】6、调优
hancoder
博客等级 码龄9年 4136粉丝 167原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值