自定义简单的(tomcat)web服务器

来源:互联网 发布:网络tv电视直播软件 编辑:程序博客网 时间:2024/05/22 07:00

  自从JSP发布之后,推出了各式各样的JSP引擎。Apache Group在完成GNUJSP1.0的开发以后,开始考虑在SUN的JSWDK基础上开发一个可以直接提供Web服务的JSP服务器,当然同时也支持Servlet, 这样Tomcat就诞生了。Tomcat是jakarta项目中的一个重要的子项目,其被JavaWorld杂志的编辑选为2001年度最具创新的java产品,同时它又是sun公司官方推荐的servlet和jsp容器,因此其越来越多的受到软件公司和开发人员的喜爱。servlet和jsp的最新规范都可以在tomcat的新版本中得到实现。其次,Tomcat是完全免费的软件,任何人都可以从互联网上自由地下载。Tomcat与Apache的组合相当完美。

      当然这次我自定义的tomcat是很简单的,只解析出普通的html页面进行响应然后回送的是字符串到浏览器,其他的css什么的自然是不不支持的,一个基于Java的web服务器用到的两个重要类:java.net.Socket和java.net.ServerSock,当然通信用的是http协议。

      好的,首先我们先新建一个tomcatServer入口类,这个类自然就是用serverSocket进行对socket的连接进行监听,然后再在线程中操作与浏览器的请求和响应:

[html] view plain copy
  1. <span style="font-size:18px;">import java.io.IOException;  
  2. import java.net.ServerSocket;  
  3. import java.net.Socket;  
  4. public class TomcatServer {  
  5.     /**  
  6.      * @param args  
  7.      *   
  8.      * tomcatserver一有客户端上来就监听  
  9.      * @throws IOException   
  10.      */  
  11.     public static void main(String[] args)  {  
  12.         int port=Integer.parseInt((String)WebProperties.getInstance().get("port"));  
  13.         ServerSocket ss=null;  
  14.         try {  
  15.             ss = new ServerSocket(port);  
  16.         } catch (IOException e) {  
  17.           
  18.             Utils.printException(e);  
  19.         }  
  20.         System.out.println(Utils.formatDate()+"\t服务器启动,监听"+ss.getLocalPort()+"端口");  
  21.         while(true){  
  22.             Socket s=null;  
  23.             try {  
  24.                 s=ss.accept();  
  25.             } catch (IOException e) {  
  26.                 // TODO Auto-generated catch block  
  27.                 Utils.printException(e);  
  28.             }  
  29.             System.out.println("客户端"+s.getRemoteSocketAddress()+"登陆上了服务器");  
  30.             //这是一个连接会话任务类,实现Runnable接口,网络操作需要启用线程  
  31.             //在会话任务类中  
  32.             HttpSessionTask hst=new HttpSessionTask(s);  
  33.             new Thread(hst).start();  
  34.         }  
  35.           
  36.     }  
  37. }</span>  

      浏览器此时是客户端,我们监听了一个端口,然后只要有客户端连接上来我们就要在HttpSession中对浏览器的请求做处理了,在这里我们要建一个配置文件用来定义资源文件的位置和端口号,这样就可以容易修改这些配置项了:

[plain] view plain copy
  1. path:c:\\  
  2. defaultpage=index.html  
  3. port=10000  
此时配置项我们只需要加载一次,解析这个文件并要做成单例的:

[html] view plain copy
  1. import java.io.IOException;  
  2. import java.io.InputStream;  
  3. import java.util.Properties;  
  4.   
  5. //要求单例  
  6. public class WebProperties extends Properties {  
  7. private static WebProperties myProperties;  
  8.       
  9.     private WebProperties() {  
  10.         //在这里完成读取db.properties文件  
  11.             InputStream iis=WebProperties.class.getClassLoader().getResourceAsStream( "web.properties");  
  12.             try {  
  13.                 this.load(   iis );  
  14.             } catch (IOException e) {  
  15.                   
  16.                 e.printStackTrace();  
  17.             }  
  18.     }  
  19.     //多个客户端上来时,防止多线程  
  20.     public synchronized static WebProperties getInstance() {  
  21.         if( myProperties==null){  
  22.              myProperties=new WebProperties();  
  23.         }  
  24.         return myProperties;  
  25.     }  
  26. }  
在HttpSession这个会话类中,需要完成接收请求和回送响应两个操作,在我们的java的web服务器中,HttpServletRequest是用来发送请求的,HttpServletResponse是用来回送响应的,我们也模仿java的这个机制,用这两个类对请求和响应做处理

HttpServletRequest类要做的是解析浏览器发来的http协议拿到请求头里的资源地址,然后HttpServletResponse得到资源地址后解析资源进行拼接协议响应头回送给客户端,这样一次请求到响应浏览器就可以显示出资源地址的内容了。 

自定义的HttpServletRequest类:

[java] view plain copy
  1. import java.io.BufferedReader;  
  2. import java.io.IOException;  
  3. import java.io.InputStream;  
  4. import java.io.InputStreamReader;  
  5. import java.util.HashMap;  
  6. import java.util.Map;  
  7. /** 
  8.  * 这个请求类对浏览器发送的协议进行解析,得到资源地址(这里只考虑get方法,参数拚在请求头中,这里解析出来后不做处理) 
  9.  * @author Administrator 
  10.  * 
  11.  */  
  12. public class HttpServletRequest {  
  13.     private String uri;  
  14.     private String method;  
  15.     private String protocolVersion;  
  16.     private Map<String,String> parameter=new HashMap<String,String>();  
  17.     private InputStream iis;  
  18.     //这个构造函数的iis是从socket中得到的输入流  
  19.     public HttpServletRequest( InputStream iis) throws IOException{  
  20.         this.iis=iis;  
  21.         parse();  
  22.     }  
  23.     //解析协议的方法   GET /company/index.html HTTP/1.1  
  24.     private void parse() throws IOException {  
  25.         BufferedReader br=new BufferedReader(new InputStreamReader(iis));  
  26.         String line=null;  
  27.         int i=0;  
  28.         if((line=br.readLine())!=null){  
  29.             if(i==0){     
  30.                 parseCommandLine(line);  
  31.             }  
  32.             i++;  
  33.         }  
  34.     }  
  35.     private void parseCommandLine(String line) {  
  36.         if(line!=null&&!"".equals(line)){  
  37.             String [] strs=line.split(" ");  
  38.             method=strs[0];  
  39.             protocolVersion=strs[2];  
  40.             if("GET".equals(method)){  
  41.                 doGet(strs[1]);  
  42.             }  
  43.         }  
  44.     }  
  45.     private void doGet(String str) {  
  46.         //解析是否有参数  
  47.         if(str.contains("?")){  
  48.             String[] strs=str.split("?");  
  49.             uri=strs[0];  
  50.             String[] ps=strs[1].split("&");  
  51.             for(String s:ps){  
  52.                 String[] pp=s.split("=");  
  53.                 parameter.put(pp[0], pp[1]);  
  54.             }  
  55.         }else{  
  56.             uri=str;  
  57.         }  
  58.           
  59.     }  
  60.     //get方法参数的类  
  61.     public String getParameter(String key) {  
  62.         String value=parameter.get(key);  
  63.         if(!value.equals("")||!(value==null)){  
  64.             return value;  
  65.         }else{  
  66.             return null;  
  67.         }  
  68.           
  69.     }  
  70.     public String getUri() {  
  71.         return uri;  
  72.     }  
  73.     public String getMethod() {  
  74.         return method;  
  75.     }  
  76.     public String getProtocolVersion() {  
  77.         return protocolVersion;  
  78.     }  
  79.       
  80. }  
自定义的HttpServletResponse类:

[java] view plain copy
  1. import java.io.File;  
  2. import java.io.FileInputStream;  
  3. import java.io.IOException;  
  4. import java.io.OutputStream;  
  5.   
  6. /** 
  7.  * 服务器响应类,这个类得到资源地址后对文件进行解析(这里只当字符全部输出), 
  8.  * 然后拼接响应头给浏览器浏览器接收后显示信息 
  9.  * @author Administrator 
  10.  * 
  11.  */  
  12. public class HttpServletResponse {  
  13.     private OutputStream oos;  
  14.     public HttpServletResponse(OutputStream oos){  
  15.         this.oos=oos;  
  16.     }  
  17.     public void redirect(String pageUrl){  
  18.         //输出流到客户端  
  19.         byte[] bs=new byte[1024];  
  20.         FileInputStream fis=null;  
  21.         File f=new File(pageUrl);  
  22.         if(!f.exists()){  
  23.             out404();  
  24.             return;  
  25.         }  
  26.         try {  
  27.             fis=new FileInputStream(f);  
  28.             StringBuffer sb=new StringBuffer();  
  29.             int length=-1;  
  30.             while((length=fis.read(bs,0,bs.length))!=-1){  
  31.                 sb.append(new String(bs,0,length,"gbk"));  
  32.             }  
  33.             //正常的时候响应的协议  
  34.             String responseHead="HTTP/1.1 200 OK\r\nContent-Type: text/html;charset=gbk\r\nContent-Length: "+sb.toString().getBytes().length+"\r\n\r\n";  
  35.             out(responseHead,sb.toString());  
  36.         } catch (Exception e) {  
  37.             // TODO Auto-generated catch block  
  38.             Utils.printException(e);  
  39.         }   
  40.     }  
  41.     private void out404() {  
  42.         String responseBody="<h1>没有页面</h1>";  
  43.         //TODO:  
  44.         String responseHead="HTTP/1.1 404 Not Found\r\nContent-Type: text/html;charset=utf-8\r\nContent=Length: "  
  45.             +responseBody.getBytes().length+"\r\n\r\n";  
  46.         try{  
  47.             out(responseBody,responseHead);  
  48.               
  49.         }catch(Exception e){  
  50.             Utils.printException(e);  
  51.         }  
  52.           
  53.     }  
  54.     private void out(String responseHead,String responseBody) throws IOException{  
  55.         oos.write(responseHead.getBytes());  
  56.         oos.write(responseBody.getBytes());  
  57.         oos.flush();  
  58.     }  
  59. }  
最后一个就是我们的会话类了,这个类进行集中处理整个流程的操作:

[java] view plain copy
  1. import java.io.IOException;  
  2. import java.io.InputStream;  
  3. import java.io.OutputStream;  
  4. import java.net.Socket;  
  5.   
  6. /** 
  7.  *  
  8.  * @author Administrator 
  9.  *获取输入流,得到客户端传来的协议 
  10.  *将协议解析一个HttpServerletRequest对象(http://localhost/compay/index.html) 
  11.  *协议 GET /company/index.html HTTP/1.1 
  12.  */  
  13. public class HttpSessionTask implements Runnable {  
  14.     private Socket s;  
  15.     private InputStream iis;  
  16.     private OutputStream oos;  
  17.     private boolean flag=true;  
  18.     public HttpSessionTask(Socket s){  
  19.         this.s=s;  
  20.         try {  
  21.             iis=s.getInputStream();  
  22.             oos=s.getOutputStream();  
  23.         } catch (IOException e) {  
  24.             Utils.printException(e);  
  25.             flag=false;  
  26.         }  
  27.           
  28.     }  
  29.     //因为http协议是一个无状态的,请求完后回应一次断开  
  30.     public void run() {  
  31.         if(flag==false){  
  32.             return;  
  33.         }  
  34.           
  35.         try {  
  36.             //创建requset对象解析http协议的请求部分   GET /company/index.html HTTP/1.1  
  37.             //得到资源地址 /kaw/index.html  
  38.             //通过配置文件找到path c:\kaw\index.html  
  39.             //再创建response对象,调用redirect(path);  
  40.             HttpServletRequest request=new HttpServletRequest(iis);  
  41.             String uri=request.getUri();  
  42.             String filepath=WebProperties.getInstance().getProperty("path")+uri;  
  43.             HttpServletResponse response=new HttpServletResponse(oos);  
  44.             response.redirect(filepath);  
  45.         } catch (IOException e) {  
  46.             // TODO Auto-generated catch block  
  47.             Utils.printException(e);  
  48.             out500(e);  
  49.         }finally{  
  50.             if(this.s!=null){  
  51.                 try {  
  52.                     s.close();  
  53.                 } catch (IOException e) {  
  54.                       
  55.                     e.printStackTrace();  
  56.                 }  
  57.             }  
  58.         }     
  59.     }  
  60.     private void out500(Exception e) {  
  61.         //拼接协议输出错误信息  
  62.         //略  
  63.           
  64.     }  
  65.   
  66. }  
好的,我们只需要在c盘放一个普通的html文件,启动tomcatserver类。

用浏览器访问地址:

网页就被读取出来了,当然这是个很简单的服务器,也只能操作普通文本,后续的学习希望可以深入服务器的学习,多多交流!




原文地址:http://blog.csdn.net/u010214269/article/details/47297285
原创粉丝点击