一、Web简介
1、什么是Web
-
Web是一种分布式应用架构
- 什么是分布式
- 大型的软件系统划分成n个子系统,每个子系统独立部署及运行不同的主机,它们之间是可以相互调用及通讯
- 什么是分布式
-
基于客户端/服务端通讯(b/s),这里的客户端就是指浏览器(brower)了
- b:浏览器
- s:服务端
-
基于浏览器访问
-
基于http协议进行数据通讯
- 客户端与服务端之间的数据通讯
2、Web的作用
-
目的分享数据、分享信息
-
数据存储到服务器,通过浏览器访问,获取数据
- 数据
- 本文内容
- 图片
- 视频
- 音频
- 数据
二、Web结构
-
描述WEB原理操作的整个过程
-
具体操作细节
-
打开浏览器输入url地址
- url地址的格式
- 协议名://WEB服务器的主机IP:端口/web应用名/访问资源路径
- url地址的格式
-
浏览器会自动将url地址封装成http协议的请求部分
-
浏览器将http协议的请求部分以流的形式发送给WEB服务器
-
WEB服务器的WEB容器就会解释http协议的请求部分,获知客户端需要访问那些资源
-
将访问资源封装到http协议的响应正文部分,以流的形式发回给到客户端(浏览器)
-
浏览器就会解释http协议的响应内容,获取响应正文数据,解释html文档,显示到浏览器
-
-
WEB结构包括
-
客户端
- 浏览器
- 作用
- 生成http协议的请求部分
-
WEB容器
- 服务器
- 作用
- 解释http协议的请求内容
- 将资源封装到http协议的响应部分,写回给客户端
-
http协议
-
url地址
-
三、http协议
1、简介
- 超文本传输协议,如何在网络传输html文档数据,就是通过此协议实现
2、特点
- 它是基于tcp/ip协议之上的应用层的协议
- 它是请求及响应的一次过程
- 它是无状态协议
- http协议具有健忘症
- 下一次请求,就会将上一次请求的数据全丢。
- http协议具有健忘症
3、协议组成部分
(图中两个空行理解成两个换行)
a、Http协议的请求部分
- 请求的提交方式(get还是post)、URI和HTTP协议的版本
POST /hello.jsp HTTP/1.1
“POST”为请求方式。
“/hello.jsp”为URI。
“HTTP/1.1”为HTTP协议版本。
- 请求头(Request Header)
- 以key:value形式描述
请求正文(Request Content)
- 以post方式提交参数,此参数的数据内容写到请求正文
四、编写一个WEB服务器
1、WEB服务端
下面的代码可以看成是一个小tomcat,看不懂直接跳过,不影响后面的学习,可以先看后面的内容,看懂后面的内容后再回来看下面的代码,可以更好的理解tomcat
代码是基于IO流的,会用到IO流的知识
package server;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
* 1、此类解析http协议请求部分
* 2、通过解释http协议,获知客户端提取什么资源
* 3、针对客户端作出响应
* */
public class HttpServer {
public static void main(String[] args) {
int port;
ServerSocket serverSocket;
try {
port = Integer.parseInt(args[0]);
}catch (Exception e) {
port = 8080; //tomcat默认端口为8080
}
try {
serverSocket = new ServerSocket(port);
System.out.println("服务器正在监听端口:" + serverSocket.getLocalPort());
while (true)//连续监听客户端
{
Socket socket=serverSocket.accept();
service(socket);
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void service(Socket socket)throws Exception
{
//获取输入流
InputStream socketIn=socket.getInputStream();
//睡眠500毫秒,使得客户端的数据发送完全,以防有时发送不完,在获取输入数据大小时报错
//得有这种思想
Thread.sleep(500);
//获取输入数据的大小
int size=socketIn.available();
//定义一个字节数组,数组长度即输入数据(请求)的大小
byte buffer[]=new byte[size];
socketIn.read(buffer);
//将字节数组转换成字符串
String request=new String(buffer);
/*解析HTTP请求*/
//获得HTTP请求的第一行
// \r\n表示回车换行,换行了说明第一行结束
int endIndex=request.indexOf("\r\n");
//当没有遇到\r\n时,indexOf返回的值是-1,当遇到时就返回当前索引值
//所以当没有遇到时(即返回-1),说明输入的数据(请求)没有换行,endIndex的值就等于请求的长度
//遇到了endIndex就等于换行的索引值
if(endIndex==-1){
endIndex=request.length();}
else
//str.substring(int beginIndex,int endIndex);截取str中从beginIndex开始
//至endIndex结束时的字符串,
{String firstLineOfRequest= request.substring(0,endIndex);}
//由此就得到第一行数据的内容
System.out.println("http请求协议的第一行数据="+firstLineOfRequest);
//解析HTTP请求的第一行
//将请求的提交方式,uri,http版本这三个按空格分开存到数组,
String[] parts=firstLineOfRequest.split(" ");
String uri="";
if(parts.length>=2)
uri=parts[1]; //获得HTTP请求中的uri
System.out.println("uri="+uri);
//将数据封装http协议的响应内容
/*
1、响应第一行
响应状态码、版本 HTTP/1.1 200 OK
2、响应头部信息
3、响应正文
*/
/*创建HTTP响应结果 */
//HTTP响应的第一行
String responseFirstLine="HTTP/1.1 200 OK\r\n";
//HTTP响应头
/*决定HTTP响应正文的类型,此处作了简化处理*/
String contentType;
if(uri.indexOf("html")!=-1 || uri.indexOf("htm")!=-1)
contentType="text/html";
else if(uri.indexOf("jpg")!=-1 || uri.indexOf("jpeg")!=-1)
contentType="image/jpeg";
else if(uri.indexOf("gif")!=-1)
contentType="image/gif";
else
contentType="application/octet-stream"; //字节流类型
String responseHeader="Content-Type:"+contentType+"\r\n\r\n";
//将uri指明的资源,以输入流的形式读取
//获得读取响应正文数据的输入流
InputStream in=HttpServer.class.getResourceAsStream("root/"+uri);
//将数据写到客户端
OutputStream outputStream=socket.getOutputStream();
//写出http协议的响应第一行内容
outputStream.write(responseFirstLine.getBytes());
//写出http协议的响应头部信息
outputStream.write(responseHeader.getBytes());
//根据uri读取到的数据内容写到响应正文
//定义一个读取响应内容的buf
byte b[]=new byte[128];
int len=-1;
while ((len=in.read(b))!=-1)
{
outputStream.write(b,0,len);
}
Thread.sleep(1000); //睡眠1秒,等待客户接收HTTP响应结果
socket.close(); //关闭TCP连接
}
}
五、编写一个支持动态资源Web服务器
1、什么动态资源
- 根据请求参数,响应内容动态修改
- (下面的代码可以看成是一个小tomcat,看不懂直接跳过,不影响后面的学习,可以先看后面的内容,看懂后面的内容后再回来看下面的代码,可以更好的理解tomcat)
2、如何实现动态资源
-
编写一个类,此类根据用户提交的参数,作出不同的响应
-
编写一个Servlet类
- 编写一个接口
package server;
import java.io.OutputStream;
public interface Servlet {
//初始化Servlet类
public void init() throws Exception;
//接受用户请求,作出不同的响应
public void service(byte[] requestBuffer, OutputStream out)throws Exception;
}
- 编写实现类
package server;
import java.io.OutputStream;
public class MyServlet implements Servlet {
@Override
public void init() throws Exception {
}
@Override
public void service(byte[] requestBuffer, OutputStream out) throws Exception {
/*获得请求参数username */
String username=null;
String request=new String(requestBuffer);
//获得HTTP请求的第一行
String firstLineOfRequest=
request.substring(0,request.indexOf("\r\n"));
//解析HTTP请求的第一行
将请求的提交方式,uri,http版本这三个按空格分开存到数组part
String[] parts=firstLineOfRequest.split(" ");
String method=parts[0]; //获得HTTP请求中的请求方式
String uri=parts[1]; //获得HTTP请求中的uri
//由于get和post提交方式是不同的,下面分情况讨论
if(method.equalsIgnoreCase("get"))
{
/*假定uri="servlet/HelloServlet?username=Tom&password=1234"*/
//parameters="username=Tom&password=1234"
String parameters=uri.substring(uri.indexOf("?"),uri.length());
//parts={"username=Tom","password=1234"};
parts=parameters.split("&");
//parts={"username","Tom"};
parts=parts[0].split("=");
username=parts[1];
}else if(method.equalsIgnoreCase("post"))
{
int locate=request.indexOf("\r\n\r\n");
//获得响应正文
String content=request.substring(locate+4,request.length());
if(content.indexOf("username=")!=-1){
/*假定content="username=Tom&password=1234"*/
//parts={"username=Tom","password=1234"};
parts=content.split("&");
//parts={"username","Tom"};
parts=parts[0].split("=");
username=parts[1];
}
}
/*创建并发送HTTP响应*/
//发送HTTP响应第一行
out.write("HTTP/1.1 200 OK\r\n".getBytes());
//发送HTTP响应头
out.write("Content-Type:text/html\r\n\r\n".getBytes());
//发送HTTP响应正文
String content="<html><head><title>HelloWorld"
+"</title></head><body>";
content+="<h1>Hello:"+username+"</h1></body><head>";
out.write(content.getBytes());
}
public static void main(String[] args) {
String uri="/servlet/myservlet?username=gec&password=1111";
String parameters=
uri.substring(uri.indexOf("?"),uri.length());
//parts={"username=Tom","password=1234"};
String[] parts= parts=parameters.split("&");
//parts={"username","Tom"};
String []parts2=parts[0].split("=");
String username=parts2[1];
System.out.println(username);
*//* parts=parts[1].split("=");
String password=parts[1];
System.out.println(password);*//*
String []parts3=parts[1].split("=");
System.out.println(parts3[1]);
}
}