初步认识Tomcat
- Tomcat 初认识
- HTTP协议
- 请求部分
- 响应部分
- Socket
- 请求端
- 响应端
- tomcat版本1,获取静态资源
- 准备工作
- 原理实现
- 代码实现
- tomcat版本2,获取动态资源
- 准备工作
- 原理实现
- 代码实现
- 总结
Tomcat 初认识
一直在用它,从来没有真正的过理解过它。
决定学习Tomcat,这是看了B站的一个编写Tomcat的视频,当然只是很简单的讲到Socket这一步就结束了。
现在将笔记记录在这里,在学习Tomcat的过程中,告诉自己一句话:
慢慢来
HTTP协议
截至到现在,我觉得HTTP协议超文本传输协议真的对我来说是一种折磨,不过看到视频里的讲解,我觉得对哦~ 。
就简单来理解,它就是两方传输信息的约定俗成的规则。
HTML协议是一种请求-响应模型
服务器端接收到来自客户端的请求,然后将请求的资源返回给客户端。
请求部分
名称 | 例子 | 说明 |
---|---|---|
请求行 | 'GET /demo.html HTTP/1.1' | GET:是请求方法;'demo.html’是请求内容;HTTP/1.1 是请求协议以及协议版本 |
请求头 | "Host:本次请求的主机路径;User-agent:本次请求的客户端的平台以及浏览器信息;Accept;Accept-Language:Accept-Encoding" | |
请求体 | 确定用户表单数据向服务器传输的格式 | Get:没有请求体;Post:由请求体 |
Accpet:客户端可以接受到的类型的信息;Accept-Language:告诉服务器客户都安可以识别的语言类型;Accept-Encoding:告诉服务器浏览器可以接收到哪些类型的压缩格式数据
响应部分
名称 | 例子 | 说明 |
---|---|---|
响应行 | ' HTTP/1.1 200 OK' | HTTP/1.1 是请求协议以及协议版本 状态码 状态描述 |
响应头 | "服务端告诉客户端服务端的信息" | 响应头和响应体之间有一个空行 |
响应体 | 服务端相应给客户端的内容,可能是html、js、css等 |
状态码
- 200 表示成功
- 404 服务器找不到请求的资源
- 500 服务器内部的错误
响应头
Date:响应的时间;content-type:响应的内容类型;content-encoding :相应内容采取的压缩格式;content-length:响应内容的长度
Socket
请求端
我们访问 链接,所以只需要实现请求端。
Socket socket = null;
InputStream is = null; //输入流
OutputStream ops = null; //输出流
try {
//1.建立一个和服务端对应的Socket对象,知名链接服务器端的域名和端口号
socket = new Socket("www.itcast.cn",80);
//2.通过socket获取到指定服务端的输出流对象
ops = socket.getOutputStream();
//3.获取到输入流
is = socket.getInputStream();
//4.将HTTP协议的请求部分发送到服务器
ops.write("GET /subject/about/index.html HTTP/1.1n".getBytes()); //操作系统默认的编码格式的字符数组
ops.write("HOST:www.itcast.cnn".getBytes());
ops.write("n".getBytes());
//5.接受来自服务器的数据并输出
int i = is.read();
while(i!=-1){
System.out.print((char)i);
i = is.read();
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
//6.释放资源
if(is!=null){
is.close();
is=null;
}
if(ops!=null){
ops.close();
ops = null;
}
if(socket!=null){
socket.close();
socket=null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
注意:在响应头、响应体、响应行之间都是需要加上换行符n的
响应端
我们直接在浏览器访问hppt://localhost:8080 ,只需要在服务器端实现代码就可以
ServerSocket serverSocket = null;
Socket socket = null;
OutputStream ops = null;
try {
//1.创建ServerSocket对象,监听本机的8080端口
serverSocket = new ServerSocket(8080);
while(true){
//2.等待来自客户端的请求 获取和和客户端对应的Socket对象
socket = serverSocket.accept();
//3.通过获取的Socket对象获取到输出流对象
ops = socket.getOutputStream();
//4.通过获取的输出流对象将HTML协议的相应部分发送到客户端
ops.write("HTTP/1.1 200 OKn".getBytes());
ops.write("Content-Type:text/html;charset=utf-8n".getBytes());
ops.write("Server:Apache-Coyote/1.1n".getBytes());
ops.write("nn".getBytes());
//将响应体放在一个对象里
StringBuilder sb = new StringBuilder();
sb.append("<html>");
sb.append("<head><title>我是标题</title></head>");
sb.append("<body>");
sb.append("<h1>i am header 1</h1>");
sb.append("</body></html>");
ops.write(sb.toString().getBytes());
ops.flush(); //这一块实际上没有用,父类的实际上是空的,没有做任何操作
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
//6.释放资源
if(ops!=null){
ops.close();
ops = null;
}
if(socket!=null){
socket.close();
socket=null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
tomcat版本1,获取静态资源
准备工作
工程下新建WebContent,然后在下面创建demo1.html 和demo2.html文件。
原理实现
代码实现
定义变量
//定义一个变量,存放服务端WebContent目录的绝对路径
public static String WEB_ROOT = System.getProperty("user.dir")+"\"+"WebContent"; // ”“是转义字符 user.dir 工程的根目录
//定义一个变量,用于存放本次请求的静态变量
private static String url="";
主函数
//创建serverSocket对象,监听8080端口
ServerSocket serverSocket = null;
Socket socket = null;
InputStream is = null;
OutputStream ops = null;
try{
serverSocket = new ServerSocket(8080);
while(true){
//获取到客户端对应的socket
socket = serverSocket.accept();
//获取到输入流对象
is = socket.getInputStream();
//获取到输出流对象
ops = socket.getOutputStream();
//读取HTTP协议请求的数据 截取客户端访问的资源名称 并赋值给url
parse(is);
//发送静态资源
sendStaticResource(ops);
}
}catch (Exception e){
e.printStackTrace();
}finally {
//6.释放资源
if(ops!=null){
ops.close();
ops = null;
}
if(socket!=null){
socket.close();
socket=null;
}
if(is!=null){
is.close();
is = null;
}
}
解析输入流,获取请求内容并赋值给url
//读取HTTP协议请求的数据 截取客户端访问的资源名称 并赋值给url
private static void parse(InputStream is)throws IOException {
//定义一个变量,存放HTTp协议的请求部分
StringBuilder sb = new StringBuilder(2048);
//定义一个数组,存放HTTP协议的请求部分
byte[] buffer = new byte[2048];
//定义一个变量i,代表存取数据到数组中,数组的大小
int i=-1;
//读取客户端发送过来的数据,将数据读取到buffer中,i表示数据量的大小
i = is.read(buffer);
//遍历字节数组,将数组中的数据追加到变量connect中
for(int j=0;j<i;j++){
sb.append((char)buffer[j]);
}
//打印HTTP协议请求部分数据
System.out.println(sb.toString());
//截取客户端请求的资源路径demo1.html 赋值给url
parserUrl(sb.toString());
}
截取客户端请求的资源路径demo1.html 赋值给url
//截取客户端请求的资源路径demo1.html 赋值给url
private static void parserUrl(String content) {
//定义两个变量 ,保存两个空格的位置
int index1,index2;
//获取到第一个空格的位置
index1 = content.indexOf(" ");
if(index1!=-1){
index2 = content.indexOf(" ",index1+1);
if(index2>index1){
url = content.substring(index1+2,index2);
}
}
System.out.println(url);
}
发送静态资源
//发送静态资源
private static void sendStaticResource(OutputStream ops) throws Exception{
//定义一个字节数组,用于存放本次请求的静态资源demo1.html的内容
byte[] bytes = new byte[2048];
//定义一个文件输入流,用户获取本次请求的资源的内容
FileInputStream fis = null;
try{
//创建文件对象File ,代表本次请求的资源demo1.html;
File file = new File(WEB_ROOT,url);
//如果文件存在
if(file.exists()){
//向客户端输出HTTP协议的响应行 响应头
ops.write("HTTP/1.1 200 OKn".getBytes());
ops.write("Server:apache-Coyote/1.1n".getBytes());
ops.write("Content-type:text/html;charset=utf-8n".getBytes());
ops.write("n".getBytes());
//获取到文件输入流对象
fis = new FileInputStream(file); //输入流输出流是相对应内存再来说,如果把一个文件的内容
//写道内存中,则是输入流;如果把一个程序写道文件里,则是相对应的输出流
int ch = fis.read(bytes);
while(ch!=-1){
//将读取到的数组中的内容通过输出流发动到客户端
ops.write(bytes,0,ch);
ch = fis.read(bytes);
}
}else{
//如果文件没有
//向客户按发送不存在
ops.write("HTTP/1.1 404 not foundn".getBytes());
ops.write("Server:apache-Coyote/1.1n".getBytes());
ops.write("Content-type:text/html;charset=utf-8n".getBytes());
ops.write("n".getBytes());
ops.write("file not foundn".getBytes());
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(fis!=null){
fis.close();
fis=null;
}
}
}
tomcat版本2,获取动态资源
准备工作
- 在webContent中创建一个conf,properties配置文件
- 创建一个接口Servlet
- 创建两个类AAServlet和BBServlet
原理实现
代码实现
servlet接口
//所有的服务端 java小程序 要实现的接口
public interface Servlet {
public void init();
public void service(InputStream is, OutputStream ops)throws IOException;
public void destroy();
}
AAServlet类
@Override
public void init() {
System.out.println("AAServlet init");
}
@Override
public void service(InputStream is, OutputStream ops) throws IOException {
System.out.println("AAServlet service");
ops.write("i am from AASERVLET".getBytes());
}
@Override
public void destroy() {
System.out.println("AAServlet destryoy");
}
conf.properties配置文件
aa = cn.itcast.mytomcat2.AAServlet
bb = cn.itcast.mytomcat2.BBServlet
服务端代码-变量定义
//服务器端
public static String WEB_ROOT = System.getProperty("user.dir")+"\"+"WebContent";
//变量 对应的key value 获取的请求的内容 所对应的java小程序的路径
public static HashMap<String,String> map = new HashMap<>();
//变量 客户端请求的内容
public static String url="";
服务端代码-静态函数:处理一些在服务器启动的时候就需要获取的配置信息
static{
//要在服务器启动之前将配置信息加载到map中
//获取对应的配置文件的内容
Properties properties = new Properties();
//加载输入流
try {
properties.load(new FileInputStream(new File(WEB_ROOT,"conf.properties")));
//输出所有的配置信息
Enumeration en = properties.propertyNames();
while(en.hasMoreElements()){
String key = (String)en.nextElement();
String value = (String)properties.getProperty(key);
map.put(key,value);
}
//二种方法
// Set set = properties.keySet();
// Iterator<String> iterator = set.iterator();
// while (iterator.hasNext()){
// String key = iterator.next();
// String value= properties.getProperty(key);
// }
} catch (IOException e) {
e.printStackTrace();
}
}
服务端代码-主函数
ServerSocket serverSocket = null;
Socket socket = null;
InputStream is=null;
OutputStream ops = null;
try {
//创建服务器端监听接口对象
serverSocket = new ServerSocket(8080);
//获取到服务器端对应的Socket
socket = serverSocket.accept();
//获取输入流
is = socket.getInputStream();
//获取输出流
ops = socket.getOutputStream();
//读取HTTP协议请求的数据 截取客户端访问的资源名称 并赋值给url
//判断本次请求的是html静态页面还是动态资源
parse(is);
if(null!=url){
if(url.indexOf(".")!=-1){
sendStaticResource(ops);
}else{
//向客户发送HTTP协议响应头、响应行 发送动态资源
sendDynamicResource(is,ops);
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
}
服务端代码-解析请求内容,并进行截取获得url
参照上一小节代码
服务端代码-发送动态资源
//给客户端发送动态资源
private static void sendDynamicResource(InputStream is,OutputStream ops) throws Exception {
try {
//获取类的路径 并通过反射的机制来运行
if(map.containsKey(url)){
Class<?> servletClass = Class.forName(map.get(url));
//向客户端输出HTTP协议的响应行 响应头
ops.write("HTTP/1.1 200 OKn".getBytes());
ops.write("Server:apache-Coyote/1.1n".getBytes());
ops.write("Content-type:text/html;charset=utf-8n".getBytes());
ops.write("n".getBytes());
Method method = servletClass.getDeclaredMethod("init");
method.invoke(servletClass.newInstance());
//运行service
method = servletClass.getDeclaredMethod("service",InputStream.class,OutputStream.class);
method.invoke(servletClass.newInstance(),is,ops);
//运行detroy
method = servletClass.getDeclaredMethod("destroy");
method.invoke(servletClass.newInstance());
//第二种映射方法
// Class class_ = Class.forName(map.get(url));
// Servlet servlet = (Servlet)class_.newInstance();
// servlet.init();
// servlet.service(is, ops);
// servlet.destroy();
}else{
ops.write("HTTP/1.1 404 not foundn".getBytes());
ops.write("Server:apache-Coyote/1.1n".getBytes());
ops.write("Content-type:text/html;charset=utf-8n".getBytes());
ops.write("n".getBytes());
ops.write("file not foundn".getBytes());
}
}catch (Exception e){
e.printStackTrace();
}finally {
}
}
注意:反射和文件内容读取都是比较基础而且比较重要的
总结
最后
以上就是甜蜜奇迹最近收集整理的关于Tomcat初认识Tomcat 初认识的全部内容,更多相关Tomcat初认识Tomcat内容请搜索靠谱客的其他文章。
发表评论 取消回复