(1) open system interconnect
OSI是Open System Interconnection的缩写,意为开放式系统互联 。OSI是一个开放性的通信系统互连参考模型,他是一个定义得非常好的协议规范。OSI模型有7层结构,每层都可以有几个子层。 OSI的7层从上到下分别是 7 应用层 6 表示层 5 会话层 4 传输层 3 网络层 2 数据链路层 1 物理层 ;其中高层(即7、6、5、4层)定义了应用程序的功能,下面3层(即3、2、1层)主要面向通过网络的端到端的数据流。
各层功能
应用层
与其它计算机进行通讯的一个应用,它是对应应用程序的通信服务的。例如,一个没有通信功能的字处理程序就不能执行通信的代码,从事字处理工作的程序员也不关心OSI的第7层。但是,如果添加了一个传输文件的选项,那么字处理器的程序员就需要实现OSI的第7层。示例:TELNET,HTTP,FTP,NFS,SMTP等。
表示层
这一层的主要功能是定义数据格式及加密。例如,FTP允许你选择以二进制或ASCII格式传输。如果选择二进制,那么发送方和接收方不改变文件的内容。如果选择ASCII格式,发送方将把文本从发送方的字符集转换成标准的ASCII后发送数据。在接收方将标准的ASCII转换成接收方计算机的字符集。示例:加密,ASCII等。
会话层
它定义了如何开始、控制和结束一个会话,包括对多个双向消息的控制和管理,以便在只完成连续消息的一部分时可以通知应用,从而使表示层看到的数据是连续的,在某些情况下,如果表示层收到了所有的数据,则用数据代表表示层。示例:RPC,SQL等。
传输层
这层的功能包括是否选择差错恢复协议还是无差错恢复协议,及在同一主机上对不同应用的数据流的输入进行复用,还包括对收到的顺序不对的数据包的重新排序功能。示例:TCP,UDP,SPX。
网络层
这层对端到端的包传输进行定义,它定义了能够标识所有结点的逻辑地址,还定义了路由实现的方式和学习的方式。为了适应最大传输单元长度小于包长度的传输介质,网络层还定义了如何将一个包分解成更小的包的分段方法。示例:IP,IPX等。
数据链路层
它定义了在单个链路上如何传输数据。这些协议与被讨论的各种介质有关。示例:ATM,FDDI等。
物理层
OSI的物理层规范是有关传输介质的特这些规范通常也参考了其他组织制定的标准。连接头、帧、帧的使用、电流、编码及光调制等都属于各种物理层规范中的内容。物理层常用多个规范完成对所有细节的定义。示例:Rj45,802.3等。
分层优点
1)人们可以很容易的讨论和学习协议的规范细节。
(2)层间的标准接口方便了工程模块化。
(3)创建了一个更好的互连环境。
(4)降低了复杂度,使程序更容易修改,产品开发的速度更快。
(5)每层利用紧邻的下层服务,更容易记住各层的功能。
(2) http协议
一、
HTTP(HyperText Transfer Protocol)是一套计算机通过网络进行通信的规则。计算机专家设计出HTTP,使HTTP客户(如Web浏览器)能够从HTTP服务器(Web服务器)请求信息和服务,HTTP目前协议的版本是1.1.HTTP是一种无状态的协议,无状态是指Web浏览器和Web服务器之间不需要建立持久的连接,这意味着当一个客户端向服务器端发出请求,然后Web服务器返回响应(response),连接就被关闭了,在服务器端不保留连接的有关信息.HTTP遵循请求(Request)/应答(Response)模型。Web浏览器向Web服务器发送请求,Web服务器处理请求并返回适当的应答。所有HTTP连接都被构造成一套请求和应答。
HTTP使用内容类型,是指Web服务器向Web浏览器返回的文件都有与之相关的类型。所有这些类型在MIME Internet邮件协议上模型化,即Web服务器告诉Web浏览器该文件所具有的种类,是HTML文档、GIF格式图像、声音文件还是独立的应用程序。大多数Web浏览器都拥有一系列的可配置的辅助应用程序,它们告诉浏览器应该如何处理Web服务器发送过来的各种内容类型。
HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤:
(1) 建立TCP连接
在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该连接是通过TCP来完成的,该协议与IP协议共同构建Internet,即著名的TCP/IP协议族,因此Internet又被称作是TCP/IP网 络。HTTP是比TCP更高层次的应用层协议,根据规则,只有低层协议建立之后才能,才能进行更层协议的连接,因此,首先要建立TCP连接,一般TCP连接的端口号是80
(2) Web浏览器向Web服务器发送请求命令
一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令
例如:GET/sample/hello.jsp HTTP/1.1
(3) Web浏览器发送请求头信息
浏览器发送其请求命令之后,还要以头信息的形式向Web服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。
(4) Web服务器应答
客户机向服务器发出请求后,服务器会客户机回送应答,
HTTP/1.1 200 OK
应答的第一部分是协议的版本号和应答状态码
(5) Web服务器发送应答头信息
正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。
(6) Web服务器向浏览器发送数据
Web服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据
(7) Web服务器关闭TCP连接
一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码
Connection:keep-alive
TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。
二、
当浏览器向Web服务器发出请求时,它向服务器传递了一个数据块,也就是请求信息,HTTP请求信息由3部分组成:
l 请求方法 URI 协议/版本
l 请求头(Request Header)
l 请求正文
for example :
GET /index.html?name=123&pwd=5456 HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept-Language: en-US,zh-CN;q=0.5
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; InfoPath.2)
Accept-Encoding: gzip, deflate
Host: localhost:8888
Connection: Keep-Alive
POST /index.html HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept-Language: en-US,zh-CN;q=0.5
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; InfoPath.2)
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: localhost:8888
Content-Length: 17
Connection: Keep-Alive
Cache-Control: no-cache
uname=123&pwd=213&fav=0&fav=1&fav=2
(1) 请求方法URI协议/版本
请求的第一行是“方法URL议/版本”:GET/sample.jsp HTTP/1.1
以上代码中“GET”代表请求方法,“/sample.jsp”表示URI,“HTTP/1.1代表协议和协议的版本。
根据HTTP标准,HTTP请求可以使用多种请求方法。例如:HTTP1.1支持7种请求方法:GET、POST、HEAD、OPTIONS、PUT、DELETE和TARCE。在Internet应用中,最常用的方法是GET和POST。
(2) 请求头(Request Header)
请求头包含许多有关的客户端环境和请求正文的有用信息。例如,请求头可以声明浏览器所用的语言,请求正文的长度等。
(3) 请求正文
请求头和请求正文之间是一个空行,这个行非常重要,它表示请求头已经结束,接下来的是请求正文。请求正文中可以包含客户提交的查询字符串信息:
name=123&pwd=5456
在以上的例子的HTTP请求中,请求的正文只有一行内容。当然,在实际应用中,HTTP请求正文可以包含更多的内容。
HTTP请求方法我这里只讨论GET方法与POST方法
l GET方法
GET方法是默认的HTTP请求方法,我们日常用GET方法来提交表单数据,然而用GET方法提交的表单数据只经过了简单的编码,同时它将作为URL的一部分向Web服务器发送,因此,如果使用GET方法来提交表单数据就存在着安全隐患上。例如
从上面的URL请求中,很容易就可以辩认出表单提交的内容。(?之后的内容)另外由于GET方法提交的数据是作为URL请求的一部分所以提交的数据量不能太大
l POST方法
POST方法是GET方法的一个替代方法,它主要是向Web服务器提交表单数据,尤其是大批量的数据。POST方法克服了GET方法的一些缺点。通过POST方法提交表单数据时,数据不是作为URL请求的一部分而是作为标准数据传送给Web服务器,这就克服了GET方法中的信息无法保密和数据量太小的缺点。因此,出于安全的考虑以及对用户隐私的尊重,通常表单提交时采用POST方法。
三、从编程的角度来讲,如果用户通过GET方法提交数据,则数据存放在QUERY_STRING环境变量中,而POST方法提交的数据则可以从标准输入流中获取。
HTTP应答与HTTP请求相似,HTTP响应也由3个部分构成,分别是:
l 协议状态版本代码描述
l 响应头(Response Header)
l 响应正文
下面是一个HTTP响应的例子:
HTTP/1.1 200 OK
Server:Apache Tomcat/5.0.12
Date:Mon,6Oct2003 13:13:33 GMT
Content-Type:text/html
Last-Moified:Mon,6 Oct 2003 13:23:42 GMT
Content-Length:112
HTTP响应示例Hello HTTP!
协议状态代码描述HTTP响应的第一行类似于HTTP请求的第一行,它表示通信所用的协议是HTTP1.1服务器已经成功的处理了客户端发出的请求(200表示成功):
HTTP/1.1 200 Ok
响应头(Response Header)响应头也和请求头一样包含许多有用的信息,例如服务器类型、日期时间、内容类型和长度等
响应正文响应正文就是服务器返回的HTML页面,响应头和正文之间也必须用空行分隔。
四
HTTP应答码
HTTP应答码也称为状态码,它反映了Web服务器处理HTTP请求状态。HTTP应答码由3位数字构成,其中首位数字定义了应答码的类型:
1XX-信息类(Information),表示收到Web浏览器请求,正在进一步的处理中
2XX-成功类(Successful),表示用户请求被正确接收,理解和处理例如:200 OK
3XX-重定向类(Redirection),表示请求没有成功,客户必须采取进一步的动作。
4XX-客户端错误(Client Error),表示客户端提交的请求有错误 例如:404 NOT
Found,意味着请求中所引用的文档不存在。
5XX-服务器错误(Server Error)表示服务器不能完成对请求的处理:如 500
对于我们Web开发人员来说掌握HTTP应答码有助于提高Web应用程序调试的效率和准确性。
(3)
packagecom.zwj.demo01;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.net.ServerSocket;importjava.net.Socket;/*** 创建服务器,并启动
*@authorAdministrator
**/
public classServer {privateServerSocket server;/***@paramargs*/
public static voidmain(String[] args) {
Server server= newServer();
server.start();
}/*** 启动方法*/
public voidstart(){try{
server= new ServerSocket(8888);this.receive();
}catch(IOException e) {
e.printStackTrace();
}
}/*** 接收客户端*/
private voidreceive(){try{
Socket client=server.accept();
StringBuilder sb=newStringBuilder();
String msg=null;
BufferedReader br= new BufferedReader(newInputStreamReader(client.getInputStream()));while((msg=br.readLine()).length()>0){
sb.append(msg);
sb.append("\r\n");
}//接收客户端的请求信息
String requestInfo =sb.toString().trim();
System.out.println(requestInfo);
}catch(IOException e) {//e.printStackTrace();
}
}/*** 听着服务器*/
public voidstop(){
}
}
Server
packagecom.zwj.demo01;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.net.ServerSocket;importjava.net.Socket;/*** 创建服务器,并启动
*@authorAdministrator
**/
public classServer2 {privateServerSocket server;/***@paramargs*/
public static voidmain(String[] args) {
Server2 server= newServer2();
server.start();
}/*** 启动方法*/
public voidstart(){try{
server= new ServerSocket(8888);this.receive();
}catch(IOException e) {
e.printStackTrace();
}
}/*** 接收客户端*/
private voidreceive(){try{
Socket client=server.accept();byte[] data=new byte[20480];int len =client.getInputStream().read(data);//接收客户端的请求信息
String requestInfo=new String(data,0,len).trim();
System.out.println(requestInfo);
}catch(IOException e) {//e.printStackTrace();
}
}/*** 听着服务器*/
public voidstop(){
}
}/*POST /log HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Content-Length: 17
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,* ;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
uname=123&pwd=123*/
Server2
登录用户名:密码:
登录server2HTML页面
带有响应的服务器名称
packagecom.zwj.demo01;importjava.io.BufferedWriter;importjava.io.IOException;importjava.io.OutputStreamWriter;importjava.net.ServerSocket;importjava.net.Socket;importjava.util.Date;/*** 创建服务器,并启动
*
* 1、请求
* 2、响应
*@authorAdministrator
**/
public classServer3 {privateServerSocket server;//换行控制符号
public static final String CRLF="\r\n";public static final String BLANK=" ";/***@paramargs*/
public static voidmain(String[] args) {
Server3 server= newServer3();
server.start();
}/*** 启动方法*/
public voidstart(){try{
server= new ServerSocket(8888);this.receive();
}catch(IOException e) {
e.printStackTrace();
}
}/*** 接收客户端*/
private voidreceive(){try{
Socket client=server.accept();byte[] data=new byte[20480];int len =client.getInputStream().read(data);//接收客户端的请求信息
String requestInfo=new String(data,0,len).trim();
System.out.println(requestInfo);//响应
StringBuilder responseContext =newStringBuilder();
responseContext.append("
HTTP响应示例" +"
Hello bjsxt!");StringBuilder response=newStringBuilder();//1) HTTP协议版本、状态代码、描述
response.append("HTTP/1.1").append(BLANK).append("200").append(BLANK).append("OK").append(CRLF);//2) 响应头(Response Head)
response.append("Server:bjsxt Server/0.0.1").append(CRLF);
response.append("Date:").append(newDate()).append(CRLF);
response.append("Content-type:text/html;charset=GBK").append(CRLF);//正文长度 :字节长度
response.append("Content-Length:").append(responseContext.toString().getBytes().length).append(CRLF);//3)正文之前
response.append(CRLF);//4)正文
response.append(responseContext);
System.out.println(responseContext);//输出流
BufferedWriter bw = new BufferedWriter(newOutputStreamWriter(client.getOutputStream()));
bw.write(response.toString());
bw.flush();
bw.close();
}catch(IOException e) {
}
}/*** 听着服务器*/
public voidstop(){
}
}/*POST /index.html HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Content-Length: 22
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
uname=zhouwuji&pwd=123
HTTP响应示例Hello bjsxt!*/Server3
分离response、server
packagecom.zwj.demo01;importjava.io.BufferedWriter;importjava.io.IOException;importjava.io.OutputStream;importjava.io.OutputStreamWriter;importjava.net.Socket;importjava.util.Date;/*** 封装响应信息
*@authorAdministrator
**/
public classResponse {//两个常量
public static final String CRLF="\r\n";public static final String BLANK=" ";//流
privateBufferedWriter bw ;//正文
privateStringBuilder content;//存储头信息
privateStringBuilder headInfo;//存储正文长度
private int len =0;publicResponse(){
headInfo=newStringBuilder();
content=newStringBuilder();
len=0;
}publicResponse(Socket client){this();try{
bw= new BufferedWriter(newOutputStreamWriter(client.getOutputStream()));
}catch(IOException e) {
headInfo=null;
}
}publicResponse(OutputStream os){this();
bw= new BufferedWriter(newOutputStreamWriter(os));
}/*** 构建正文*/
publicResponse print(String info){
content.append(info);
len+=info.getBytes().length;return this;
}/*** 构建正文+回车*/
publicResponse println(String info){
content.append(info).append(CRLF);
len+=(info+CRLF).getBytes().length;return this;
}/*** 构建响应头*/
private void createHeadInfo(intcode){//1) HTTP协议版本、状态代码、描述
headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK);switch(code){case 200:
headInfo.append("OK");break;case 404:
headInfo.append("NOT FOUND");break;case 505:
headInfo.append("SEVER ERROR");break;
}
headInfo.append(CRLF);//2) 响应头(Response Head)
headInfo.append("Server:bjsxt Server/0.0.1").append(CRLF);
headInfo.append("Date:").append(newDate()).append(CRLF);
headInfo.append("Content-type:text/html;charset=GBK").append(CRLF);//正文长度 :字节长度
headInfo.append("Content-Length:").append(len).append(CRLF);
headInfo.append(CRLF);//分隔符
}//推送到客户端
void pushToClient(int code) throwsIOException{if(null==headInfo){
code=500;
}
createHeadInfo(code);//头信息+分割符
bw.append(headInfo.toString());//正文
bw.append(content.toString());
bw.flush();
}public voidclose(){
CloseUtil.closeIO(bw);
}
}
Response
packagecom.zwj.demo01;importjava.io.BufferedWriter;importjava.io.IOException;importjava.io.OutputStreamWriter;importjava.net.ServerSocket;importjava.net.Socket;importjava.util.Date;/*** 创建服务器,并启动
*
* 1、请求
* 2、响应
*@authorAdministrator
**/
public classServer4 {privateServerSocket server;public static final String CRLF="\r\n";public static final String BLANK=" ";/***@paramargs*/
public static voidmain(String[] args) {
Server4 server= newServer4();
server.start();
}/*** 启动方法*/
public voidstart(){try{
server= new ServerSocket(8888);this.receive();
}catch(IOException e) {
e.printStackTrace();
}
}/*** 接收客户端*/
private voidreceive(){try{
Socket client=server.accept();byte[] data=new byte[20480];int len =client.getInputStream().read(data);//接收客户端的请求信息
String requestInfo=new String(data,0,len).trim();
System.out.println(requestInfo);//响应
Response rep=newResponse(client.getOutputStream());
rep.println("
HTTP响应示例");rep.println("
Hello server!");rep.pushToClient(200);
}catch(IOException e) {
}
}/*** 听着服务器*/
public voidstop(){
}
}
Server4
packagecom.zwj.demo01;importjava.io.Closeable;importjava.net.DatagramSocket;importjava.net.ServerSocket;importjava.net.Socket;public classCloseUtil {/*** 关闭IO流*/
/*public static void closeIO(Closeable... io){
for(Closeable temp:io){
try {
if (null != temp) {
temp.close();
}
} catch (Exception e) {
}
}
}*/
/*** 使用泛型方法实现关闭IO流
*@paramio*/
public static voidcloseIO(T... io){for(Closeable temp:io){try{if (null !=temp) {
temp.close();
}
}catch(Exception e) {
}
}
}public static voidcloseSocket(ServerSocket socket){try{if (null !=socket) {
socket.close();
}
}catch(Exception e) {
}
}public static voidcloseSocket(Socket socket){try{if (null !=socket) {
socket.close();
}
}catch(Exception e) {
}
}public static voidcloseSocket(DatagramSocket socket){try{if (null !=socket) {
socket.close();
}
}catch(Exception e) {
}
}
}
CloseUtil
分离成request、response、servlet、dispatch加入多线程的服务器
packagecom.zwj.demo01;importjava.io.IOException;importjava.net.Socket;/*** 一个请求与响应 就一个此对象
*@authorAdministrator
**/
public class Dispatcher implementsRunnable{privateSocket client;privateRequest req;privateResponse rep;private int code=200;
Dispatcher(Socket client){this.client=client;try{
req=newRequest(client.getInputStream());
rep=newResponse(client.getOutputStream());
}catch(IOException e) {//e.printStackTrace();
code =500;return;
}
}
@Overridepublic voidrun() {
Servlet serv=newServlet();
serv.service(req,rep);try{
rep.pushToClient(code);//推送到客户端
} catch(IOException e) {//e.printStackTrace();
}try{
rep.pushToClient(500);
}catch(IOException e) {
e.printStackTrace();
}
CloseUtil.closeSocket(client);
}
}
Dispatcher
packagecom.zwj.demo01;importjava.io.InputStream;importjava.io.UnsupportedEncodingException;importjava.util.ArrayList;importjava.util.Arrays;importjava.util.HashMap;importjava.util.List;importjava.util.Map;importjava.util.StringTokenizer;/*** 封装request
*@authorAdministrator
**/
public classRequest {//请求方式
privateString method;//请求资源
privateString url;//请求参数
private Map>parameterMapValues;//内部
public static final String CRLF="\r\n";privateInputStream is;//请求的信息
privateString requestInfo;publicRequest(){
method="";
url="";
parameterMapValues=new HashMap>();
requestInfo="";
}publicRequest(InputStream is){this();this.is=is;try{byte[] data = new byte[20480];int len =is.read(data);
requestInfo= new String(data, 0, len);
}catch(Exception e) {return;
}//分析请求信息
parseRequestInfo();
}/*** 分析请求信息*/
private voidparseRequestInfo(){if(null==requestInfo ||(requestInfo=requestInfo.trim()).equals("")){return;
}/*** =====================================
* 从信息的首行分解出 :请求方式 请求路径 请求参数(get可能存在)
* 如:GET /index.html?name=123&pwd=5456 HTTP/1.1
*
* 如果为post方式,请求参数可能在 最后正文中
*
* 思路:
* 1)请求方式 :找出第一个/ 截取即可
* 2)请求资源:找出第一个/ HTTP/
* =====================================*/String paramString=""; //接收请求参数//1、获取请求方式
String firstLine =requestInfo.substring(0,requestInfo.indexOf(CRLF));int idx =requestInfo.indexOf("/"); ///的位置
this.method=firstLine.substring(0, idx).trim();
String urlStr=firstLine.substring(idx,firstLine.indexOf("HTTP/")).trim();if(this.method.equalsIgnoreCase("post")){this.url=urlStr;
paramString=requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim();
}else if(this.method.equalsIgnoreCase("get")){if(urlStr.contains("?")){ //是否存在参数
String[] urlArray=urlStr.split("\\?");this.url=urlArray[0];
paramString=urlArray[1];//接收请求参数
}else{this.url=urlStr;
}
}//不存在请求参数
if(paramString.equals("")){return;
}//2、将请求参数封装到Map中
parseParams(paramString);
}private voidparseParams(String paramString){//分割 将字符串转成数组
StringTokenizer token=new StringTokenizer(paramString,"&");while(token.hasMoreTokens()){
String keyValue=token.nextToken();
String[] keyValues=keyValue.split("=");if(keyValues.length==1){//Arrays.copyOf 扩容
keyValues =Arrays.copyOf(keyValues, 2);
keyValues[1] =null;
}
String key= keyValues[0].trim();
String value= null==keyValues[1]?null:decode(keyValues[1].trim(),"gbk");//转换成Map 分拣
if(!parameterMapValues.containsKey(key)){
parameterMapValues.put(key,new ArrayList());
}
List values =parameterMapValues.get(key);
values.add(value);
}
}/*** 解决中文
*@paramvalue
*@paramcode
*@return
*/
privateString decode(String value,String code){try{returnjava.net.URLDecoder.decode(value, code);
}catch(UnsupportedEncodingException e) {//e.printStackTrace();
}return null;
}/*** 根据页面的name 获取对应的多个值
*@paramargs*/
publicString[] getParameterValues(String name){
List values=null;if((values=parameterMapValues.get(name))==null){return null;
}else{return values.toArray(new String[0]);
}
}/*** 根据页面的name 获取对应的单个值
*@paramargs*/
publicString getParameter(String name){
String[] values=getParameterValues(name);if(null==values){return null;
}return values[0];
}publicString getUrl() {returnurl;
}
}
Request
packagecom.zwj.demo01;importjava.io.BufferedWriter;importjava.io.IOException;importjava.io.OutputStream;importjava.io.OutputStreamWriter;importjava.net.Socket;importjava.util.Date;/*** 封装响应信息
*@authorAdministrator
**/
public classResponse {//两个常量
public static final String CRLF="\r\n";public static final String BLANK=" ";//流
privateBufferedWriter bw ;//正文
privateStringBuilder content;//存储头信息
privateStringBuilder headInfo;//存储正文长度
private int len =0;publicResponse(){
headInfo=newStringBuilder();
content=newStringBuilder();
len=0;
}publicResponse(Socket client){this();try{
bw= new BufferedWriter(newOutputStreamWriter(client.getOutputStream()));
}catch(IOException e) {
headInfo=null;
}
}publicResponse(OutputStream os){this();
bw= new BufferedWriter(newOutputStreamWriter(os));
}/*** 构建正文*/
publicResponse print(String info){
content.append(info);
len+=info.getBytes().length;return this;
}/*** 构建正文+回车*/
publicResponse println(String info){
content.append(info).append(CRLF);
len+=(info+CRLF).getBytes().length;return this;
}/*** 构建响应头*/
private void createHeadInfo(intcode){//1) HTTP协议版本、状态代码、描述
headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK);switch(code){case 200:
headInfo.append("OK");break;case 404:
headInfo.append("NOT FOUND");break;case 505:
headInfo.append("SEVER ERROR");break;
}
headInfo.append(CRLF);//2) 响应头(Response Head)
headInfo.append("Server:bjsxt Server/0.0.1").append(CRLF);
headInfo.append("Date:").append(newDate()).append(CRLF);
headInfo.append("Content-type:text/html;charset=GBK").append(CRLF);//正文长度 :字节长度
headInfo.append("Content-Length:").append(len).append(CRLF);
headInfo.append(CRLF);//分隔符
}//推送到客户端
void pushToClient(int code) throwsIOException{if(null==headInfo){
code=500;
}
createHeadInfo(code);//头信息+分割符
bw.append(headInfo.toString());//正文
bw.append(content.toString());
bw.flush();
}public voidclose(){
CloseUtil.closeIO(bw);
}
}
Response
packagecom.zwj.demo01;importjava.io.IOException;importjava.net.ServerSocket;importjava.net.Socket;/*** 创建服务器,并启动
*
* 1、请求
* 2、响应
*@authorAdministrator
**/
public classServer7 {privateServerSocket server;public static final String CRLF="\r\n";public static final String BLANK=" ";private boolean isShutDown= false;/***@paramargs*/
public static voidmain(String[] args) {
Server7 server= newServer7();
server.start();
}/*** 启动方法*/
public voidstart(){
start(8888);
}/*** 指定端口的启动方法*/
public void start(intport){try{
server= newServerSocket(port);this.receive();
}catch(IOException e) {//e.printStackTrace();
stop();
}
}/*** 接收客户端*/
private voidreceive(){try{while(!isShutDown){new Thread(newDispatcher(server.accept())).start();
}
}catch(IOException e) {//e.printStackTrace();
stop();
}
}/*** 停止服务器*/
public voidstop(){
isShutDown=true;
CloseUtil.closeSocket(server);
}
}
Server7
packagecom.zwj.demo01;public classServlet {public voidservice(Request req,Response rep){
rep.println("
HTTP响应示例");rep.println("
");rep.println("欢迎:").println(req.getParameter("uname")).println("回来");
rep.println("");
}
}
Servlet
packagecom.zwj.demo01;importjava.io.Closeable;importjava.net.DatagramSocket;importjava.net.ServerSocket;importjava.net.Socket;public classCloseUtil {/*** 关闭IO流*/
/*public static void closeIO(Closeable... io){
for(Closeable temp:io){
try {
if (null != temp) {
temp.close();
}
} catch (Exception e) {
}
}
}*/
/*** 使用泛型方法实现关闭IO流
*@paramio*/
public static voidcloseIO(T... io){for(Closeable temp:io){try{if (null !=temp) {
temp.close();
}
}catch(Exception e) {
}
}
}public static voidcloseSocket(ServerSocket socket){try{if (null !=socket) {
socket.close();
}
}catch(Exception e) {
}
}public static voidcloseSocket(Socket socket){try{if (null !=socket) {
socket.close();
}
}catch(Exception e) {
}
}public static voidcloseSocket(DatagramSocket socket){try{if (null !=socket) {
socket.close();
}
}catch(Exception e) {
}
}
}
CloseUtil
sax解析xml文件 注:要继承defaulthandle类 里面有5个方法 startdocument() 、startelentment()得到元素名称 、charcter()得到values值、endelement()、enddocument() 解析式一行一行解析,
和dom4j是把xml变成dom树进行解析
packagecom.bjsxt.xml;importjava.io.IOException;importjava.util.List;importjavax.xml.parsers.ParserConfigurationException;importjavax.xml.parsers.SAXParser;importjavax.xml.parsers.SAXParserFactory;importorg.xml.sax.SAXException;public classParseDemo01 {/***@paramargs
*@throwsSAXException
*@throwsParserConfigurationException
*@throwsIOException*/
public static void main(String[] args) throwsParserConfigurationException, SAXException, IOException {//1、获取解析工厂
SAXParserFactory factory=SAXParserFactory.newInstance();//2、从解析工厂获取解析器
SAXParser parse =factory.newSAXParser();//3、加载文档 Document 注册处理器//4、编写处理器
PersonHandler handler=newPersonHandler();
parse.parse(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("com/bjsxt/xml/person.xml")
,handler );
List persons =handler.getPersons();for(Person p:persons){
System.out.println(p.getName()+"-->"+p.getAge());
}
}
}
ParseDemo01
packagecom.bjsxt.xml;public classPerson {privateString name;private intage;publicPerson() {//TODO Auto-generated constructor stub
}public Person(String name, intage) {super();this.name =name;this.age =age;
}publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}public intgetAge() {returnage;
}public void setAge(intage) {this.age =age;
}
}
Person
至尊宝
9000
白晶晶
7000
person.xml
package com.bjsxt.xml;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* 存储对象
* @author Administrator
*
*/
public class PersonHandler extends DefaultHandler {
private Listpersons;
private Person person;
private String tag;//记录标签名
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
//System.out.println("处理文档开始");
persons =new ArrayList();
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
System.out.println("开始一个元素" +qName);
if(null!=qName){
tag=qName;
}
if(null!=qName &&qName.equals("person")){
person =new Person();
}
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
String str =new String(ch,start,length);
if(null!=tag &&tag.equals("name")){
//System.out.println(new String(ch,start,length));
person.setName(str);
}else if(null!=tag &&tag.equals("age")){
Integer age = Integer.valueOf(str);
person.setAge(age);
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
//System.out.println("结束一个元素" +qName);
if(qName.equals("person")){
this.persons.add(person);
}
tag =null;
}
@Override
public void endDocument() throws SAXException {
System.out.println("文档处理结束");
}
public ListgetPersons() {
return persons;
}
public void setPersons(Listpersons) {
this.persons = persons;
}
}
PersonHandler
简单的服务器最终版本
packagecom.zwj.server;importjava.io.IOException;importjava.net.Socket;importcom.zwj.servlet.Servlet;importcom.zwj.util.CloseUtil;/*** 一个请求与响应 就一个此对象
*@authorAdministrator
**/
public class Dispatcher implementsRunnable{privateSocket client;privateRequest req;privateResponse rep;private int code=200;
Dispatcher(Socket client){this.client=client;try{
req=newRequest(client.getInputStream());
rep=newResponse(client.getOutputStream());
}catch(IOException e) {//e.printStackTrace();
code =500;return;
}
}
@Overridepublic voidrun() {try{
Servlet serv=WebApp.getServlet(req.getUrl());if(null==serv){this.code=404; //找不到处理
}else{
serv.service(req, rep);
}
rep.pushToClient(code);//推送到客户端
}catch(Exception e) {
e.printStackTrace();this.code=500;
}try{
rep.pushToClient(500);
}catch(IOException e) {
e.printStackTrace();
}
req.close();
rep.close();
CloseUtil.closeSocket(client);
}
}
Dispatcher
packagecom.zwj.server;/*
login
com.bjsxt.server.demo4.LoginServlet
*/
public classEntity {privateString name;privateString clz;publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}publicString getClz() {returnclz;
}public voidsetClz(String clz) {this.clz =clz;
}
}
Entity
packagecom.zwj.server;importjava.util.ArrayList;importjava.util.List;/*
login
/login
login
/log
*/
public classMapping {privateString name;private ListurlPattern;publicMapping(){
urlPattern=new ArrayList();
}publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}public ListgetUrlPattern() {returnurlPattern;
}public void setUrlPattern(ListurlPattern) {this.urlPattern =urlPattern;
}
}
Mapping
packagecom.zwj.server;importjava.io.InputStream;importjava.io.UnsupportedEncodingException;importjava.util.ArrayList;importjava.util.Arrays;importjava.util.HashMap;importjava.util.List;importjava.util.Map;importjava.util.StringTokenizer;importcom.zwj.util.CloseUtil;/*** 封装request
*@authorAdministrator
**/
public classRequest {//请求方式
privateString method;//请求资源
privateString url;//请求参数
private Map>parameterMapValues;//内部
public static final String CRLF="\r\n";privateInputStream is;privateString requestInfo;publicRequest(){
method="";
url="";
parameterMapValues=new HashMap>();
requestInfo="";
}publicRequest(InputStream is){this();this.is=is;try{byte[] data = new byte[20480];int len =is.read(data);
requestInfo= new String(data, 0, len);
}catch(Exception e) {return;
}//分析请求信息
parseRequestInfo();
}/*** 分析请求信息*/
private voidparseRequestInfo(){if(null==requestInfo ||(requestInfo=requestInfo.trim()).equals("")){return;
}/*** =====================================
* 从信息的首行分解出 :请求方式 请求路径 请求参数(get可能存在)
* 如:GET /index.html?name=123&pwd=5456 HTTP/1.1
*
* 如果为post方式,请求参数可能在 最后正文中
*
* 思路:
* 1)请求方式 :找出第一个/ 截取即可
* 2)请求资源:找出第一个/ HTTP/
* =====================================*/String paramString=""; //接收请求参数//1、获取请求方式
String firstLine =requestInfo.substring(0,requestInfo.indexOf(CRLF));int idx =requestInfo.indexOf("/"); ///的位置
this.method=firstLine.substring(0, idx).trim();
String urlStr=firstLine.substring(idx,firstLine.indexOf("HTTP/")).trim();if(this.method.equalsIgnoreCase("post")){this.url=urlStr;
paramString=requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim();
}else if(this.method.equalsIgnoreCase("get")){if(urlStr.contains("?")){ //是否存在参数
String[] urlArray=urlStr.split("\\?");this.url=urlArray[0];
paramString=urlArray[1];//接收请求参数
}else{this.url=urlStr;
}
}//不存在请求参数
if(paramString.equals("")){return;
}//2、将请求参数封装到Map中
parseParams(paramString);
}private voidparseParams(String paramString){//分割 将字符串转成数组
StringTokenizer token=new StringTokenizer(paramString,"&");while(token.hasMoreTokens()){
String keyValue=token.nextToken();
String[] keyValues=keyValue.split("=");if(keyValues.length==1){
keyValues=Arrays.copyOf(keyValues, 2);
keyValues[1] =null;
}
String key= keyValues[0].trim();
String value= null==keyValues[1]?null:decode(keyValues[1].trim(),"gbk");//转换成Map 分拣
if(!parameterMapValues.containsKey(key)){
parameterMapValues.put(key,new ArrayList());
}
List values =parameterMapValues.get(key);
values.add(value);
}
}/*** 解决中文
*@paramvalue
*@paramcode
*@return
*/
privateString decode(String value,String code){try{returnjava.net.URLDecoder.decode(value, code);
}catch(UnsupportedEncodingException e) {//e.printStackTrace();
}return null;
}/*** 根据页面的name 获取对应的多个值
*@paramargs*/
publicString[] getParameterValues(String name){
List values=null;if((values=parameterMapValues.get(name))==null){return null;
}else{return values.toArray(new String[0]);
}
}/*** 根据页面的name 获取对应的单个值
*@paramargs*/
publicString getParameter(String name){
String[] values=getParameterValues(name);if(null==values){return null;
}return values[0];
}publicString getUrl() {returnurl;
}public voidclose(){
CloseUtil.closeIO(is);
}
}
Request
packagecom.zwj.server;importjava.io.BufferedWriter;importjava.io.IOException;importjava.io.OutputStream;importjava.io.OutputStreamWriter;importjava.net.Socket;importjava.util.Date;importcom.zwj.util.CloseUtil;/*** 封装响应信息
*@authorAdministrator
**/
public classResponse {//两个常量
public static final String CRLF="\r\n";public static final String BLANK=" ";//流
privateBufferedWriter bw ;//正文
privateStringBuilder content;//存储头信息
privateStringBuilder headInfo;//存储正文长度
private int len =0;publicResponse(){
headInfo=newStringBuilder();
content=newStringBuilder();
len=0;
}publicResponse(Socket client){this();try{
bw= new BufferedWriter(newOutputStreamWriter(client.getOutputStream()));
}catch(IOException e) {
headInfo=null;
}
}publicResponse(OutputStream os){this();
bw= new BufferedWriter(newOutputStreamWriter(os));
}/*** 构建正文*/
publicResponse print(String info){
content.append(info);
len+=info.getBytes().length;return this;
}/*** 构建正文+回车*/
publicResponse println(String info){
content.append(info).append(CRLF);
len+=(info+CRLF).getBytes().length;return this;
}/*** 构建响应头*/
private void createHeadInfo(intcode){//1) HTTP协议版本、状态代码、描述
headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK);switch(code){case 200:
headInfo.append("OK");break;case 404:
headInfo.append("NOT FOUND");break;case 505:
headInfo.append("SEVER ERROR");break;
}
headInfo.append(CRLF);//2) 响应头(Response Head)
headInfo.append("Server:bjsxt Server/0.0.1").append(CRLF);
headInfo.append("Date:").append(newDate()).append(CRLF);
headInfo.append("Content-type:text/html;charset=GBK").append(CRLF);//正文长度 :字节长度
headInfo.append("Content-Length:").append(len).append(CRLF);
headInfo.append(CRLF);//分隔符
}//推送到客户端
void pushToClient(int code) throwsIOException{if(null==headInfo){
code=500;
}
createHeadInfo(code);//头信息+分割符
bw.append(headInfo.toString());//正文
bw.append(content.toString());
bw.flush();
}public voidclose(){
CloseUtil.closeIO(bw);
}
}
Response
packagecom.zwj.server;importjava.io.IOException;importjava.net.ServerSocket;importcom.zwj.util.CloseUtil;/*** 创建服务器,并启动
*
* 1、请求
* 2、响应
*@authorAdministrator
* java 世界里可以不手写的尽量用配置,能用约定的就不用配置, 约定>配置>手写*/
public classServer {privateServerSocket server;public static final String CRLF="\r\n";public static final String BLANK=" ";private boolean isShutDown= false;/***@paramargs*/
public static voidmain(String[] args) {
Server server= newServer();
server.start();
}/*** 启动方法*/
public voidstart(){
start(8888);
}/*** 指定端口的启动方法*/
public void start(intport){try{
server= newServerSocket(port);this.receive();
}catch(IOException e) {//e.printStackTrace();
stop();
}
}/*** 接收客户端*/
private voidreceive(){try{while(!isShutDown){new Thread(newDispatcher(server.accept())).start();
}
}catch(IOException e) {//e.printStackTrace();
stop();
}
}/*** 停止服务器*/
public voidstop(){
isShutDown=true;
CloseUtil.closeSocket(server);
}
}
Server
packagecom.zwj.server;importjava.util.HashMap;importjava.util.Map;/*** 上下文
*@authorAdministrator
**/
public classServletContext {//为每一个servlet取个别名//login -->com.bjsxt.server.demo03.LoginServlet
private Mapservlet ;//url -->login///log -->login///login -->login
private Mapmapping;
ServletContext(){
servlet=new HashMap();
mapping=new HashMap();
}public MapgetServlet() {returnservlet;
}public void setServlet(Mapservlet) {this.servlet =servlet;
}public MapgetMapping() {returnmapping;
}public void setMapping(Mapmapping) {this.mapping =mapping;
}
}
ServletContext
packagecom.zwj.server;importjava.util.List;importjava.util.Map;importjavax.xml.parsers.SAXParser;importjavax.xml.parsers.SAXParserFactory;importcom.zwj.servlet.Servlet;public classWebApp {private staticServletContext contxt;static{try{//获取解析工厂
SAXParserFactory factory =SAXParserFactory.newInstance();//获取解析器
SAXParser sax =factory.newSAXParser();//指定xml+处理器
WebHandler web = newWebHandler();
sax.parse(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("WEB_INFO/web.xml"), web);//将list 转成Map
contxt =newServletContext();
Map servlet =contxt.getServlet();//servlet-name servlet-class
for(Entity entity:web.getEntityList()){
servlet.put(entity.getName(), entity.getClz());
}//url-pattern servlet-name
Map mapping =contxt.getMapping();for(Mapping mapp:web.getMappingList()){
List urls =mapp.getUrlPattern();for(String url:urls ){
mapping.put(url, mapp.getName());
}
}
}catch(Exception e) {
}
}public static Servlet getServlet(String url) throwsInstantiationException, IllegalAccessException, ClassNotFoundException{if((null==url)||(url=url.trim()).equals("")){return null;
}//根据字符串(完整路径)创建对象//return contxt.getServlet().get(contxt.getMapping().get(url));
String name=contxt.getServlet().get(contxt.getMapping().get(url));return (Servlet)Class.forName(name).newInstance();//确保空构造存在
}
}
WebApp
packagecom.zwj.server;importjava.util.ArrayList;importjava.util.List;importorg.xml.sax.Attributes;importorg.xml.sax.SAXException;importorg.xml.sax.helpers.DefaultHandler;public class WebHandler extendsDefaultHandler{private ListentityList;private ListmappingList;privateEntity entity;privateMapping mapping;privateString beginTag ;private booleanisMap;
@Overridepublic void startDocument() throwsSAXException {//文档解析开始
entityList =new ArrayList() ;
mappingList=new ArrayList() ;
}
@Overridepublic voidstartElement(String uri, String localName, String qName,
Attributes attributes)throwsSAXException {//开始元素
if(null!=qName){
beginTag=qName;if(qName.equals("servlet")){
isMap=false;
entity=newEntity();
}else if(qName.equals("servlet-mapping")){
isMap=true;
mapping=newMapping();
}
}
}
@Overridepublic void characters(char[] ch, int start, intlength)throwsSAXException {//处理内容
if(null!=beginTag){
String str=newString(ch,start,length);if(isMap ){if(beginTag.equals("servlet-name")){
mapping.setName(str);
}else if(beginTag.equals("url-pattern")){
mapping.getUrlPattern().add(str);
}
}else{if(beginTag.equals("servlet-name")){
entity.setName(str);
}else if(beginTag.equals("servlet-class")){
entity.setClz(str);
}
}
}
}
@Overridepublic voidendElement(String uri, String localName, String qName)throwsSAXException {//结束元素
if(null!=qName){if(qName.equals("servlet")){
entityList.add(entity);
}else if(qName.equals("servlet-mapping")){
mappingList.add(mapping);
}
}
beginTag=null;
}
@Overridepublic void endDocument() throwsSAXException {//文档解析结束
}/*public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
//获取解析工厂
SAXParserFactory factory =SAXParserFactory.newInstance();
//获取解析器
SAXParser sax =factory.newSAXParser();
//指定xml+处理器
WebHandler web = new WebHandler();
sax.parse(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("com/bjsxt/server/demo4/web.xml")
,web);
System.out.println(web.getEntityList());
}*/
public ListgetEntityList() {returnentityList;
}public void setEntityList(ListentityList) {this.entityList =entityList;
}public ListgetMappingList() {returnmappingList;
}public void setMappingList(ListmappingList) {this.mappingList =mappingList;
}
}
WebHandler
packagecom.zwj.servlet;importcom.zwj.server.Request;importcom.zwj.server.Response;public class LoginWeb extendsServlet {
@Overridepublic void doGet(Request req, Response rep) throwsException {
rep.println("success.....");
}
@Overridepublic void doPost(Request req, Response rep) throwsException {//TODO Auto-generated method stub
}
}
LoginWeb
packagecom.zwj.servlet;importcom.zwj.server.Request;importcom.zwj.server.Response;/*** 抽象为一个父类
*@authorAdministrator
**/
public abstract classServlet {public void service(Request req,Response rep) throwsException{this.doGet(req,rep);this.doPost(req,rep);
}protected abstract void doGet(Request req,Response rep) throwsException;protected abstract void doPost(Request req,Response rep) throwsException;
}
Servlet
packagecom.zwj.util;importjava.io.Closeable;importjava.net.DatagramSocket;importjava.net.ServerSocket;importjava.net.Socket;public classCloseUtil {/*** 关闭IO流*/
/*public static void closeIO(Closeable... io){
for(Closeable temp:io){
try {
if (null != temp) {
temp.close();
}
} catch (Exception e) {
}
}
}*/
/*** 使用泛型方法实现关闭IO流
*@paramio*/
public static voidcloseIO(T... io){for(Closeable temp:io){try{if (null !=temp) {
temp.close();
}
}catch(Exception e) {
}
}
}public static voidcloseSocket(ServerSocket socket){try{if (null !=socket) {
socket.close();
}
}catch(Exception e) {
}
}public static voidcloseSocket(Socket socket){try{if (null !=socket) {
socket.close();
}
}catch(Exception e) {
}
}public static voidcloseSocket(DatagramSocket socket){try{if (null !=socket) {
socket.close();
}
}catch(Exception e) {
}
}
}
CloseUtil
login
com.zwj.servlet.LoginWeb
login
/g
/y
web.xml