获取字节,交给Servlet
Tomcat
核心就是交由一个Context
,放入里面的Servlet
socket
编程,获取调用方法,封装request
对象
在一个Tomcat
里面,不用根据ip
区分,就只用域名区分
PipeLine
经过Valve
的思路
socket
网络编程 nio/bio
网络io
模型
不行的啊,发现他的讲授思路完全就是按照源码来讲解,就是说直接讲源码,我觉得根本没有必要把源码全部看懂,我就需要简单实现一个就可以,所以后面的源码我就不去看了
通过不同的IO
模型实现不同的获取socket
套接字
对于tcp
协议来说,首先socket
函数创建socket
实例
之后bind
函数绑定端口号
之后是状态转换的函数listen
, connect
分别变成被动监听和主动连接的状态,同时内核创建两个队列,半连接队列和全连接队列,connect
激活tcp
三次握手,成功建立连接的放入全连接队列,系统调用accpet
获得套接字,即使没有发送消息也会一直阻塞等待该socket
的消息,如果socket
关闭的话,那就继续下面的操作,可能会继续调用accept
获取新的已经连接好的套接字
文件数据一般地首先经过内核模式copy
到用户模式,因此需要copy
四次
如果使用zero-copy
的技术,那就是直接在kernel
模式直接完成
另外最终的zero-copy
技术就是使用socket
直接记录索引,从而实现拷贝两次,实现zero-copy
IO
的各种流是阻塞的。这意味着,当一个线程调用read()
或 write()
时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。 NIO
的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变得可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO
的空闲时间用于在其它通道上执行IO
操作,所以一个单独的线程现在可以管理多个输入和输出通道channel
初始化对应的标志位,以及使用工厂模式创建服务端监听套接字
Connector
实现了Runnable
接口,但是此时并没有开启线程执行run
方法,主要介绍一下start
方法,首先保证阻塞队列processor
池中有足够的processor
注意到初始化processor
都是通过这个方法实现的,基本的思路就是processor
里面有thread
的成员变量,然后初始化实例然后执行,每次创建processor
之后会阻塞在await
方法处,等待有分配的套接字进行处理,否则一直阻塞在此处
在执行process
实际处理请求结束之后,会回收到阻塞队列里面去,recyle
方法看上去有问题,其实只在开启线程之后,保证空闲的线程被回收,不会让线程重复回收,所以其实也没有问题,因为就是创建之后同步地立马放到阻塞队列中,但是可能会再阻塞队列中获取到执行的,但是这个时候的assign
方法就会阻塞线程,但是重复回收是不会执行的,因此recyle
的代码的都是同步执行的
然后创建线程执行run
方法,保证不断监听accpet
获取已建立的套接字,创建processor
,分配套接字,获取processor
的方式,要么是通过获取已经回收的阻塞队列中的,要么就是直接创建,直接创建也参考线程池的做法,创建当前线程的时候就会分配资源开启线程
基本上通过重新封装connector
, processor
实现对应的功能,主要是熟悉nio
面向channel
和buffer
的流程,然后把select
的流程加入到web server
中
NIO
的实现有很大的bug
,首先是每次处理完都需要及时的cancel
和remove
, 否则考虑到并发的原因,有可能导致重复获得相同的socket
最终造成空请求的问题
这一点要非常注意,一直在改这个bug
, 下次一定要注意
另外一个就是空轮询的问题,虽然我没有遇到,但是还是要注意
还有就是自己写的线程池容易出bug