手写Tomcat服务器
预备知识
编写服务器用到的知识点
1) Socket 编程
2) HTML
3) HTTP 协议
4) 反射
5) XML 解析
6) 服务器编写
Socket编程
https://www.cnblogs.com/bfcs/p/10790130.html
HTML知识
HTML:HyperText Markup Language 超文本标记语言用于描述网页文档的一种标记语言
表单(form):与用户之间进行交互
method:请求方式 get/post
get 数据量小,安全性低,默认方式
post 数据量大,安全性高
action:请求的服务器路径
id :(用户的的浏览器在文档里区分唯一性)前端区分唯一性,js 中
name:名称,后端(服务器)区分唯一性,获取值,只要提交数据给后台(服务器)必须存在 name
<html>
<head>
<title>登陆界面</title>
</head>
<body>
<form action="" method="post" >
<p>用户名:<input type="text" name="username" id="name"/></p>
<p>密码:<input type="password" name="password" id="pwd"/></p>
<input type="submit" value="提交"/>
</form>
</body>
</html>
HTTP协议
协议
1) 应用层:HTTP、FTP、TELNET、SNMP、DNS
2) 传输层:TCP、UDP
3) 网络层:IP
HTTP 协议简介
HTTP:超文本传输协议,是网络应用层的协议,建立在 TCP/IP 协议基础上,HTTP 使用可靠的 TCP 连接,默认端口为 80。
用户打开 Web 浏览器(常见的 HTTP 客户端),输入 URL地址,就能接收到远程 HTTP 服务器端发送过来的网页,即HTTP 遵循请求(Request)/应答(Response)模型。
Web 浏览器向 Web 服务器发送请求,Web 服务器处理请求并返回适当的应答,所有 HTTP 连接都被构造成一套请求与应答。
HTTP 协议严格规定了 HTTP 请求和 HTTP 响应的数据格式
HTTP 请求格式
1) 请求方式、URI(统一资源定位符)、HTTP 协议/版本
2) 请求头 Request Header
请求头包含许多有关客户端环境和请求正文的有用信息。例如,请求头可以声明浏览器所用的语言,请求正文的长度等。
3) 请求正文 Requet Content (只有在 post 方式才有)请求头和请求正文之间必须有符号行(回车符或行结束符),与请求头分开。这个行非常重要,它表示请求头已结束,接
下来的是请求正文。 通常 post 方式的数据存放于此,请求正文中可以包含客户提交的查询字符串等信息。在实际应用中,HTTP 请求正文可以包含更多的内容
HTTP响应格式
1) HTTP 协议版本、状态代码、描述
2) 响应头(Response Head)
3) 响应正文(Respose Content)
Tomcat
是 SUN 公司推出的小型 Servlet/JSP 调试工具)的基础上发展起来的一个优秀的 Servlet 容器,Tomcat本身完全用 Java 语言编写
Tomcat 使用
1) 配置 Tomcat
a) JAVA_HOME Java JDK 的根目录
b) CATALINA_HOME Tomcat 根目录
2) 启动和关闭 Tomcat
启动 Tomcat 服务器:startup.bat 本地主机8080端口
关闭 Tomcat 服务器:shutdown.bat
3) 部署项目到服务器
在 webapps 目录下新建目录存放.html 页面 访问页面
Tomcat 的运行原理
客户浏览器发出要求,访问特定的 Servlet 的请求。
1) Tomcat 服务器接收到客户请求并解析。
2) Tomcat 服 务 器 创 建 一 个 ServletRequest 对 象 , 在ServletRequest 对象中包含了客户请求信息及其他关于客户的信息,如请求头,请求正文,以及客户机的 IP 地址等。
3) Tomcat 服务器创建一个 ServletResponse 对象
4) Tomcat 服务器调用客户所请求的 Servlet 的 service 服务方法,并且把 ServletRequst 对象和 ServletResponse 对象做为参数传给该服务方法。
5) Servlet 从 ServletRequest 对象中可获取客户的请求信息。
6) Servlet 利用 ServletResponse 对象来生成响应结果。
7) Tomcat 服务器把 Servlet 生成的响应结果发送给客户。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
手写服务器项目
1.搭建项目框架
2.编写XML文档
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<servlet-name>login</servlet-name>
<serlvet-class>com.bjsxt.servlet.LoginServlet</serlvet-class>
</servlet>
<servlet-mapping>
<serlvet-name>login</serlvet-name>
<url-pattern>/login</url-pattern>
<url-pattern>/log</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>register</servlet-name>
<serlvet-class>com.bjsxt.servlet.RegisterServlet</serlvet-class>
</servlet>
<servlet-mapping>
<serlvet-name>register</serlvet-name>
<url-pattern>/reg</url-pattern>
<url-pattern>/register</url-pattern>
<url-pattern>/regis</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>favicon</servlet-name>
<serlvet-class>com.bjsxt.servlet.FaviconServlet</serlvet-class>
</servlet>
<servlet-mapping>
<serlvet-name>favicon</serlvet-name>
<url-pattern>/favicon.ico</url-pattern> </servlet-mapping>
</web-app>
3.编写 IOCloseUtil 类
import java.io.Closeable;
import java.io.IOException; public class IOCloseUtil { //用于关闭所有流
public static void closeAll(Closeable...close) { //可变参数
for (Closeable closeable : close) {
if(closeable != null) {
try {
closeable.close();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
}
4.DOM4J 解析 XML 配置文件
1)Entity 实体类的编写
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.omg.CORBA.PUBLIC_MEMBER; public class WebDom4j { //用于解析XML
private List<Entitty> entityList;//用于存储N多Entity,而每一个Entity都是servlet-name与servlet-class
private List<Mapping> mappingList;//用于存储N多Mapping,而每一个Mapping都是一个servlet-name与多个url-pattern //公有取值赋值方法
public List<Entitty> getEntityList() {
return entityList;
}
public void setEntityList(List<Entitty> entityList) {
this.entityList = entityList;
}
public List<Mapping> getMappingList() {
return mappingList;
}
public void setMappingList(List<Mapping> mappingList) {
this.mappingList = mappingList;
} //构造方法
public WebDom4j() {
entityList = new ArrayList<Entitty>();
mappingList = new ArrayList<Mapping>();
}
//获取Document对象的方法
public Document getDocument() { //Document英语翻译:文件;文档
//alt+shift+z包围异常快捷键
try {
//(1)创建SAXReader对象
SAXReader reader = new SAXReader();
//(2)调用read()方法
return reader.read(new File("src/WEB_INFO/web.xml"));
} catch (DocumentException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
return null;
}
//把获取到的Document对象解析
public void parse(Document doc) {
//(1)获取根元素
Element root = doc.getRootElement(); //web-app
//(2)解析servlet
for(Iterator<Element> ite = root.elementIterator("servlet"); ite.hasNext();) {
Element subElement = ite.next();//得到每一个servlet
//创建一个实体类
Entitty ent = new Entitty();//用于存储servlet-name与servlet-class
for(Iterator<Element> subite = subElement.elementIterator(); subite.hasNext();) {
Element ele = subite.next(); //可能是servlet-name,也可能是servlet-class
if("servlet-name".equals(ele.getName())) {
ent.setName(ele.getText()); //给实体类中的name赋值
}else if ("servlet-class".equals(ele.getName())) {
ent.setClazz(ele.getText());
}
}
//经过上面的循环后Entity有值了,把Entity添加到集合中
entityList.add(ent);
}
//解析servlet-mapping
for(Iterator<Element> ite = root.elementIterator("servlet-mapping"); ite.hasNext();) {
Element subEle = ite.next();//得到每一个servlet-mapping
//创建一个mapping类对象
Mapping map = new Mapping();
//解析servlet-mapping下的子元素
for(Iterator<Element> subite = subEle.elementIterator(); subite.hasNext();) {
Element ele = subite.next();//可能是servlet-name,也可能是url-pattern
if("servlet-name".equals(ele.getName())) {
map.setName(ele.getText());
}else if("url-pattern".equals(ele.getName())){
//获取集合对象,调用集合对象的添加方法,添加元素
map.getUrlPattern().add(ele.getText());
}
}
//mapping添加到集合中
mappingList.add(map);
}
}
}
2)Mapping 实体类的编写
/**
* <servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
<url-pattern>/log</url-pattern>
</servlet-mapping>
* @author CHB
*
*/ import java.util.ArrayList;
import java.util.List; public class Mapping { //映射关系 多个路径访问共享资源 servlet-name和url-pattern对应的实体类 多个资源与小名之间的关系
private String name;//servlet-name
private List<String> urlPattern;//url-pattern //公有取值赋值方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getUrlPattern() {
return urlPattern;
}
public void setUrlPattern(List<String> urlPattern) {
this.urlPattern = urlPattern;
}
//构造方法
public Mapping() {
urlPattern = new ArrayList<String>();
}
public Mapping(String name, List<String> urlPattern) {
super();
this.name = name;
this.urlPattern = urlPattern;
}
}
3)解析 XML 文件,WebDom4j类的编写
导入Dom4j的jar包:在项目下新建文件夹lib,把jar包复制进去,导入后右键jar包选择构建路径再选择添加至构建路径
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.omg.CORBA.PUBLIC_MEMBER; public class WebDom4j { //用于解析XML
private List<Entitty> entityList;//用于存储N多Entity,而每一个Entity都是servlet-name与servlet-class
private List<Mapping> mappingList;//用于存储N多Mapping,而每一个Mapping都是一个servlet-name与多个url-pattern //公有取值赋值方法
public List<Entitty> getEntityList() {
return entityList;
}
public void setEntityList(List<Entitty> entityList) {
this.entityList = entityList;
}
public List<Mapping> getMappingList() {
return mappingList;
}
public void setMappingList(List<Mapping> mappingList) {
this.mappingList = mappingList;
} //构造方法
public WebDom4j() {
entityList = new ArrayList<Entitty>();
mappingList = new ArrayList<Mapping>();
}
//获取Document对象的方法
private Document getDocument() { //Document英语翻译:文件;文档
//alt+shift+z包围异常快捷键
try {
//(1)创建SAXReader对象
SAXReader reader = new SAXReader();
//(2)调用read()方法
return reader.read(new File("src/WEB_INFO/web.xml"));
} catch (DocumentException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
return null;
}
//把获取到的Document对象解析
public void parse(Document doc) {
//(1)获取根元素
Element root = doc.getRootElement(); //web-app
//(2)解析servlet
for(Iterator<Element> ite = root.elementIterator("servlet"); ite.hasNext();) {
Element subElement = ite.next();//得到每一个servlet
//创建一个实体类
Entitty ent = new Entitty();//用于存储servlet-name与servlet-class
for(Iterator<Element> subite = subElement.elementIterator(); subite.hasNext();) {
Element ele = subite.next(); //可能是servlet-name,也可能是servlet-class
if("servlet-name".equals(ele.getName())) {
ent.setName(ele.getText()); //给实体类中的name赋值
}else if ("servlet-class".equals(ele.getName())) {
ent.setClazz(ele.getText());
}
}
//经过上面的循环后Entity有值了,把Entity添加到集合中
entityList.add(ent);
}
//解析servlet-mapping
for(Iterator<Element> ite = root.elementIterator("servlet-mapping"); ite.hasNext();) {
Element subEle = ite.next();//得到每一个servlet-mapping
//创建一个mapping类对象
Mapping map = new Mapping();
//解析servlet-mapping下的子元素
for(Iterator<Element> subite = subEle.elementIterator(); subite.hasNext();) {
Element ele = subite.next();//可能是servlet-name,也可能是url-pattern
if("servlet-name".equals(ele.getName())) {
map.setName(ele.getText());
}else if("url-pattern".equals(ele.getName())){
//获取集合对象,调用集合对象的添加方法,添加元素
map.getUrlPattern().add(ele.getText());
}
}
//mapping添加到集合中
mappingList.add(map);
}
}
}
5.反射创建servlet对象
1)编写 ServletContext 类:Servlet 上下文,就是一个容器,用于存储映射关系
import java.util.HashMap;
import java.util.Map; public class ServletContext { //上下文 Entity与Mapping的映射关系 实体与映射关系类
private Map<String, String> servlet;//key是servlet-name,值是servlet-class
private Map<String, String> mapping;//hashmap键不能重复,值却可以,key是url-pattern, 值是servlet-name //公有的取值赋值方法
public Map<String, String> getServlet() {
return servlet;
}
public void setServlet(Map<String, String> servlet) {
this.servlet = servlet;
}
public Map<String, String> getMapping() {
return mapping;
}
public void setMapping(Map<String, String> mapping) {
this.mapping = mapping;
} //构造方法
public ServletContext() {
servlet = new HashMap<String, String>();
mapping = new HashMap<String, String>();
}
}
2)编写 WebApp 类
a) 初始化程序运行的数据
b) 根据不同的 url 创建所请求的 Servlet 对象
import java.util.List;
import java.util.Map; import javax.print.attribute.standard.Severity; import cn.chb.servlet.Servlet; /* a) 初始化程序运行的数据
b) 根据不同的 url 创建所请求的 Servlet 对象
* */ public class WebApp { //app应用程序
private static ServletContext context;
static {//静态初始化代码块
context = new ServletContext();
//分别获取对应关系的Map集合
Map<String, String> servlet = context.getServlet();
Map<String, String> mapping = context.getMapping();
//解析XML文件对象
WebDom4j web = new WebDom4j();
web.parse(web.getDocument());//解析XML并把数据放到了entityList和mappingList当中
//获取解析XML之后的List集合
List<Entitty> entityList = web.getEntityList();
List<Mapping> mappingList = web.getMappingList(); //将List集合中的数据存储到Map集合
for(Entitty entity:entityList) {
servlet.put(entity.getName(), entity.getClazz());
}
for(Mapping map:mappingList) {
//遍历url-pattern集合
List<String> urlPattern = map.getUrlPattern();
for(String s:urlPattern) {
mapping.put(s, map.getName());
}
}
}
/**
* 根据url创建不同的servlet对象
* @param url
* @return
*
*/
public static Servlet getServlet(String url){
if(url == null||url.trim().equals("")) {
return null;
}
try {
//如果url正确
String servletName = context.getMapping().get(url);//根据key(url)获取值(servlet-name)
//根据servlet-name得到对应的servlet-class
String servletClass = context.getServlet().get(servletName);//等到的是一个完整的包名+类名字符串
//使用反射创建servlet对象
Class<?> clazz = Class.forName(servletClass);
//调用无参构造方法创建servlet对象
Servlet servlet = (Servlet)clazz.newInstance();
return servlet;
} catch (ClassNotFoundException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (InstantiationException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
return null;
}
}
6.封装 Request_method_url
1) 编写 Server: 启动服务 关闭服务
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket; import com.bjsxt.servlet.Servlet;
import com.bjsxt.util.IOCloseUtil; public class Server {//服务器,用于启动和停止服务
private ServerSocket server;
private boolean isShutDown=false;//默认没有出错
public static void main(String[] args) {
Server server=new Server();//创建服务器对象
server.start();
}
public void start(){
this.start(8888);
}
public void start(int port){
try {
server=new ServerSocket(port);
this.receive(); //调用接收请求信息的方法
} catch (IOException e) {
isShutDown=true;
}
}
private void receive() {
try {
while(!isShutDown){
//(1)监听
Socket client=server.accept();
//创建线程类的对象
Dispatcher dis=new Dispatcher(client);
//创建线程的代理类,并启动线程
new Thread(dis).start();
} } catch (IOException e) {
this.stop();//关闭服务器
} }
public void stop(){
isShutDown=true;
IOCloseUtil.closeAll(server);
}
}
2)编写 HTML
<html>
<head>
<title>登陆</title>
</head>
<body>
<form action="http://127.0.1:8888/log" method="get" >
<p>用户名:<input type="text" name="username" id="username"/></p>
<p>密码:<input type="password" name="pwd" id="password"/></p>
<p>
爱好:<input type="checkbox" name="hobby" value="ball"/>足球
<input type="checkbox" name="hobby" value="read"/>读书
<input type="checkbox" name="hobby" value="pain"/>画画
</p>
<p><input type="submit" value="登陆"/></p>
<input type="submit" value="提交"/>
</form>
</body>
</html>
3) 封装 Request_method_url
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map; public class Request { /*请求类*/
private InputStream is;//输入流
private String requestInfo;//请求字符串:请求方式,路径,参数,协议/协议版本,请求正文
private String method;//请求方式
private String url;//请求的url //输入框中的name为key,值为输入的内容
/*
* key:username value:chb
* key:pwd value:123456
*/
private Map<String, List<String>> parametermapValues;//参数
private static final String CRLF="\r\n";//换行
private static final String BLANK=" ";//空格
//构造方法,初始化属性
public Request() {
parametermapValues = new HashMap<String, List<String>>();
method = "";
requestInfo = "";
url = "";
}
public Request(InputStream is) {
this();
this.is = is;
try {
byte [] buf = new byte [20480];
int len = this.is.read(buf);
requestInfo = new String(buf, 0, len);
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
//调用本类中分解请求信息的方法
this.parseRequestInfo();
}
//分解请求信息的方法 方式、路径、参数
private void parseRequestInfo() {
String paraString ="";//用于存储请求参数
//获取请求参数的第一行
String firstLine=requestInfo.substring(0, requestInfo.indexOf(CRLF)).trim();//从0开始到第一个换行
//分解出请求方式
int index = firstLine.indexOf("/");//找出斜线的位置GET /(这里) HTTP/1.1
this.method = firstLine.substring(0, index).trim();//trim()去掉空格
//分解url,可能包含参数,也可能不包含参数
String urlString = firstLine.substring(index, firstLine.indexOf("HTTP/")).trim();
//判断请求方式是GET还是POST
if("get".equalsIgnoreCase(this.method)) {//GET包含请求参数
if(urlString.contains("?")) {//包含有问号,说明有参数
String [] urlArray = urlString.split("\\?");//以?号分割获取参数
this.url = urlArray[0];
paraString = urlArray[1];
}else {
this.url = urlString;
}
}else {//POST不包含请求参数,参数在请求正文
this.url = urlString;
//最后一个换行到结尾是请求正文
paraString = requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim();
}
if(paraString.equals("")) {//如果没有参数
return;
}
}
//username=chbt&pwd=123&hobby=ball&hobby=paint
/**
* username=chb
* pwd=123
* hobby=ball
* hobby=paint
*
* username=
* @param prarString
*/
private void parseParam(String prarString){
String [] token=prarString.split("&");
for(int i=0;i<token.length;i++){
String keyValues=token[i];
String []keyValue=keyValues.split("="); //username chb pwd 123
if (keyValue.length==1) { //username=
keyValue=Arrays.copyOf(keyValue, 2);
keyValue[1]=null;
}
//将 表单元素的name与name对应的值存储到Map集合
String key=keyValue[0].trim();
String value=keyValue[1]==null?null:decode(keyValue[1].trim(), "utf-8");
//放到集合中存储
if (!parametermapValues.containsKey(key)) {
parametermapValues.put(key, new ArrayList<String>());
}
List<String> values=parametermapValues.get(key);
values.add(value);
}
}
//根据表单元素的name获取多个值
private String [] getParamterValues(String name){
//根据key获取value
List<String> values=parametermapValues.get(name);
if (values==null) {
return null;
}else{
return values.toArray(new String [0] );
} }
private String getParamter(String name){
//调用本类中根据name获取多个值的方法
String [] values=this.getParamterValues(name);
if (values==null) {
return null;
}else{
return values[0];
}
} //处理中文,因类浏览器对中文进行了编码,进行解码
private String decode(String value,String code){
try {
return URLDecoder.decode(value, code);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
7.封装 Response
1) 构造响应头
2) 推送到客户端
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException; import com.bjsxt.util.IOCloseUtil; public class Response {//响应
private StringBuilder headInfo;//响应头
private StringBuilder content;//响应内容
private int length;//响应内容的长度
//流
private BufferedWriter bw; //两个常量,换行和空格
private static final String CRLF="\r\n";//换行
private static final String BLANK=" ";//空格 //构造方法
public Response() {
headInfo=new StringBuilder();
content=new StringBuilder(); }
//带参构造方法
public Response(OutputStream os){
this();//调用本类的无参构造方法
try {
bw=new BufferedWriter(new OutputStreamWriter(os, "utf-8"));
} catch (UnsupportedEncodingException e) {
headInfo=null;
} }
//构造正文部分
public Response print(String info){
content.append(info);
try {
length+=info.getBytes("utf-8").length;
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return this;
}
public Response println(String info){
content.append(info).append(CRLF);
try {
length+=(info+CRLF).getBytes("utf-8").length;
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return this;
} //构造响应头 private void createHeadInfo(int code){
headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK);
switch (code) {
case 200:
headInfo.append("OK");
break;
case 500:
headInfo.append("SERVER ERROR");
break;
default:
headInfo.append("NOT FOUND");
break;
}
headInfo.append(CRLF);
headInfo.append("Content-Type:text/html;charset=utf-8").append(CRLF);
headInfo.append("Content-Length:"+length).append(CRLF);
headInfo.append(CRLF);
}
/**
* 推送到客户机的浏览器
* @param code
*/
public void pushToClient(int code){
if (headInfo==null) {
code=500;
}
try {
//调用本类中的构造响应头
this.createHeadInfo(code);
bw.write(headInfo.toString());
bw.write(content.toString());
bw.flush();
this.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void close(){
IOCloseUtil.closeAll(bw);
}
}
3)编写相应的 Servlet 构造响应内容
import com.bjsxt.server.Request;
import com.bjsxt.server.Response; public abstract class Servlet { //是所有的请求的Servlet的父类
public void service(Request req,Response rep) throws Exception{
this.doGet( req, rep);
this.doPost( req, rep);
}
public abstract void doGet(Request req,Response rep) throws Exception;
public abstract void doPost(Request req,Response rep) throws Exception;
}
import com.bjsxt.server.Request;
import com.bjsxt.server.Response; public class LoginServlet extends Servlet { @Override
public void doGet(Request req, Response rep) throws Exception {
//获取请求参数
String name=req.getParameter("username");
String pwd=req.getParameter("pwd"); if(this.login(name, pwd)){
//调用响应中的构建内容的方
rep.println(name+"登录成功");
}else{
rep.println(name+"登录失败,对不起,账号或密码不正确");
} }
private boolean login(String name,String pwd){
if ("bjsxt".equals(name)&&"123".equals(pwd)) {
return true;
}
return false;
} @Override
public void doPost(Request req, Response rep) throws Exception {
// TODO Auto-generated method stub }
}
import com.bjsxt.server.Request;
import com.bjsxt.server.Response; public class FaviconServlet extends Servlet { @Override
public void doGet(Request req, Response rep) throws Exception {
// TODO Auto-generated method stub } @Override
public void doPost(Request req, Response rep) throws Exception {
// TODO Auto-generated method stub } }
8.封装分发器实现多线程
import java.io.IOException;
import java.net.Socket; import com.bjsxt.servlet.Servlet;
import com.bjsxt.util.IOCloseUtil; /**
* 一个请求与响应就是一个Dispatcher
* @author Administrator
*
*/
public class Dispatcher implements Runnable {
private Request req;
private Response rep;
private Socket client;
private int code=200;//状态码
//构造方法初始化属性
public Dispatcher(Socket client) {
//将局部变量的值赋给成员变量
this.client=client;
try {
req=new Request(this.client.getInputStream());
rep=new Response(this.client.getOutputStream());
} catch (IOException e) {
code=500;
return ;
}
}
@Override
public void run() {
//根据不同的url创建指定的Servlet对象
//System.out.println(req.getUrl());
Servlet servlet=WebApp.getServlet(req.getUrl());
if (servlet==null) {
this.code=404;
}else{
//调用相应的Servlet中的service方法
try {
servlet.service(req,rep);
} catch (Exception e) {
this.code=500;
}
}
//将响应结果推送到客户机的浏览器
rep.pushToClient(code);
IOCloseUtil.closeAll(client);
} }
手写Tomcat服务器的更多相关文章
- JavaSE 手写 Web 服务器(一)
原文地址:JavaSE 手写 Web 服务器(一) 博客地址:http://www.extlight.com 一.背景 某日,在 Java 技术群中看到网友讨论 tomcat 容器相关内容,然后想到自 ...
- 手写Tomcat
学习JavaWeb之后,只知道如何部署项目到Tomcat中,而并不了解其内部如何运行,底层原理为何,因此写下此篇博客初步探究一下.学习之前需要知识铺垫已列出:Tomcat目录结构.HTTP协议.IO. ...
- JavaSE 手写 Web 服务器(二)
原文地址:JavaSE 手写 Web 服务器(二) 博客地址:http://www.extlight.com 一.背景 在上一篇文章 <JavaSE 手写 Web 服务器(一)> 中介绍了 ...
- 黑马vue---40、结合Node手写JSONP服务器剖析JSONP原理
黑马vue---40.结合Node手写JSONP服务器剖析JSONP原理 一.总结 一句话总结: 服务端可以返回js代码给script标签,那么标签会执行它,并且可带json字符串作为参数,这样就成功 ...
- 【项目】手写FTP服务器-C++实现FTP服务器
X_FTP_server 手写FTP服务器-C++实现FTP服务器 项目Gitee链接:https://gitee.com/hsby/ftp_Server 简介 一个基于libevent的高并发FTP ...
- 手写Javaweb服务器
简单web服务器 回忆socket 创建客服端(在httpClient_1包下) public class Client { public static void main(String[] a ...
- 手写tomcat——编写一个提供servlet能力的 http服务器
点击查看代码 package com.grady.diytomcat; import com.grady.diytomcat.handler.RequestHandler; import org.do ...
- 手写tomcat——编写一个echo http服务器
核心代码如下: public class DiyTomcat1 { public void run() throws IOException { ServerSocket serverSocket = ...
- 利用html 5 websocket做个山寨版web聊天室(手写C#服务器)
在之前的博客中提到过看到html5 的websocket后很感兴趣,终于可以摆脱长轮询(websocket之前的实现方式可以看看Developer Works上的一篇文章,有简单提到,同时也说了web ...
随机推荐
- VOC数据集 目标检测
最近在做与目标检测模型相关的工作,很多都要求VOC格式的数据集. PASCAL VOC挑战赛 (The PASCAL Visual Object Classes )是一个世界级的计算机视觉挑战赛, P ...
- kali渗透综合靶机(五)--zico2靶机
kali渗透综合靶机(五)--zico2靶机 靶机地址:https://www.vulnhub.com/series/zico2,137/#modal210download 一.主机发现 1.netd ...
- OpenCV.Net基于傅里叶变换进行文本的旋转校正
本文描述一种利用OpenCV及傅里叶变换识别图片中文本旋转角度并自动校正的方法,由于对C#比较熟,因此本文将使用OpenCVSharp. 文章参考了http://johnhany.net/2013/1 ...
- pycharm替换文件中所有相同字段方法
1.打开要修改的文件 2.ctrl r调出替换功能,如图所示: 3.上面红框是需要更改的部分,下面红框是想要更改为部分,编辑后,点击“replace all”即可
- Java学习——注解
Java学习——注解 摘要:本文主要介绍了Java开发常用的注解,以及如何自定义注解. 部分内容来自以下博客: https://www.cnblogs.com/Qian123/p/5256084.ht ...
- 在ie下转换时间戳出错
在将特定格式转换为时间戳的时候,我们通常的做法事new Date(str).getTime(), 这个方法在谷歌上是可行的,但是在ie上需要注意一点,就是这个str如果是“2019-11-15”的格式 ...
- flink 并行计数器实现
1.flink实现计数器的灵感来源于Hadoop的MapReduce计算框架里的理念. flink通过实现Accumulator接口实现并行计数.并行管理是由flink实现的. public inte ...
- LeetCode——Duplicate Emails(使用group by以及having解决分组统计结果)
Write a SQL query to find all duplicate emails in a table named Person. +----+---------+ | Id | Emai ...
- InnoDB Multi-Versioning
InnoDB 是一个数据多版本的存储引擎,它会保持它修改的数据的旧版本数据以此来支持事务特性,比如并发操作和事务的回滚.这些旧版本数据存储在一个叫做rollback segment的数据结构中(回滚段 ...
- django项目中cxselect三级联动
下载cxselect插件放在static文件夹下 前端引入 <script src="/static/js/jQuery-1.8.2.min.js"></scri ...