自从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的连接进行监听,然后再在线程中操作与浏览器的请求和响应:
<span style="font-size:18px;">import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class TomcatServer { /** * @param args * * tomcatserver一有客户端上来就监听 * @throws IOException */ public static void main(String[] args) { int port=Integer.parseInt((String)WebProperties.getInstance().get("port")); ServerSocket ss=null; try { ss = new ServerSocket(port); } catch (IOException e) { Utils.printException(e); } System.out.println(Utils.formatDate()+"\t服务器启动,监听"+ss.getLocalPort()+"端口"); while(true){ Socket s=null; try { s=ss.accept(); } catch (IOException e) { // TODO Auto-generated catch block Utils.printException(e); } System.out.println("客户端"+s.getRemoteSocketAddress()+"登陆上了服务器"); //这是一个连接会话任务类,实现Runnable接口,网络操作需要启用线程 //在会话任务类中 HttpSessionTask hst=new HttpSessionTask(s); new Thread(hst).start(); } } }</span>
浏览器此时是客户端,我们监听了一个端口,然后只要有客户端连接上来我们就要在HttpSession中对浏览器的请求做处理了,在这里我们要建一个配置文件用来定义资源文件的位置和端口号,这样就可以容易修改这些配置项了:
path:c:\defaultpage=index.html port=10000
此时配置项我们只需要加载一次,解析这个文件并要做成单例的:
import java.io.IOException; import java.io.InputStream; import java.util.Properties; //要求单例 public class WebProperties extends Properties { private static WebProperties myProperties; private WebProperties() { //在这里完成读取db.properties文件 InputStream iis=WebProperties.class.getClassLoader().getResourceAsStream( "web.properties"); try { this.load( iis ); } catch (IOException e) { e.printStackTrace(); } } //多个客户端上来时,防止多线程 public synchronized static WebProperties getInstance() { if( myProperties==null){ myProperties=new WebProperties(); } return myProperties; } }
在HttpSession这个会话类中,需要完成接收请求和回送响应两个操作,在我们的java的web服务器中,HttpServletRequest是用来发送请求的,HttpServletResponse是用来回送响应的,我们也模仿java的这个机制,用这两个类对请求和响应做处理
HttpServletRequest类要做的是解析浏览器发来的http协议拿到请求头里的资源地址,然后HttpServletResponse得到资源地址后解析资源进行拼接协议响应头回送给客户端,这样一次请求到响应浏览器就可以显示出资源地址的内容了。
自定义的HttpServletRequest类:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; /** * 这个请求类对浏览器发送的协议进行解析,得到资源地址(这里只考虑get方法,参数拚在请求头中,这里解析出来后不做处理) * @author Administrator * */ public class HttpServletRequest { private String uri; private String method; private String protocolVersion; private Map<String,String> parameter=new HashMap<String,String>(); private InputStream iis; //这个构造函数的iis是从socket中得到的输入流 public HttpServletRequest( InputStream iis) throws IOException{ this.iis=iis; parse(); } //解析协议的方法 GET /company/index.html HTTP/1.1 private void parse() throws IOException { BufferedReader br=new BufferedReader(new InputStreamReader(iis)); String line=null; int i=0; if((line=br.readLine())!=null){ if(i==0){ parseCommandLine(line); } i++; } } private void parseCommandLine(String line) { if(line!=null&&!"".equals(line)){ String [] strs=line.split(" "); method=strs[0]; protocolVersion=strs[2]; if("GET".equals(method)){ doGet(strs[1]); } } } private void doGet(String str) { //解析是否有参数 if(str.contains("?")){ String[] strs=str.split("?"); uri=strs[0]; String[] ps=strs[1].split("&"); for(String s:ps){ String[] pp=s.split("="); parameter.put(pp[0], pp[1]); } }else{ uri=str; } } //get方法参数的类 public String getParameter(String key) { String value=parameter.get(key); if(!value.equals("")||!(value==null)){ return value; }else{ return null; } } public String getUri() { return uri; } public String getMethod() { return method; } public String getProtocolVersion() { return protocolVersion; } }
自定义的HttpServletResponse类:
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; /** * 服务器响应类,这个类得到资源地址后对文件进行解析(这里只当字符全部输出), * 然后拼接响应头给浏览器浏览器接收后显示信息 * @author Administrator * */ public class HttpServletResponse { private OutputStream oos; public HttpServletResponse(OutputStream oos){ this.oos=oos; } public void redirect(String pageUrl){ //输出流到客户端 byte[] bs=new byte[1024]; FileInputStream fis=null; File f=new File(pageUrl); if(!f.exists()){ out404(); return; } try { fis=new FileInputStream(f); StringBuffer sb=new StringBuffer(); int length=-1; while((length=fis.read(bs,0,bs.length))!=-1){ sb.append(new String(bs,0,length,"gbk")); } //正常的时候响应的协议 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"; out(responseHead,sb.toString()); } catch (Exception e) { // TODO Auto-generated catch block Utils.printException(e); } } private void out404() { String responseBody="<h1>没有页面</h1>"; //TODO: String responseHead="HTTP/1.1 404 Not Found\r\nContent-Type: text/html;charset=utf-8\r\nContent=Length: " +responseBody.getBytes().length+"\r\n\r\n"; try{ out(responseBody,responseHead); }catch(Exception e){ Utils.printException(e); } } private void out(String responseHead,String responseBody) throws IOException{ oos.write(responseHead.getBytes()); oos.write(responseBody.getBytes()); oos.flush(); } }
最后一个就是我们的会话类了,这个类进行集中处理整个流程的操作:
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; /** * * @author Administrator *获取输入流,得到客户端传来的协议 *将协议解析一个HttpServerletRequest对象(http://localhost/compay/index.html) *协议 GET /company/index.html HTTP/1.1 */ public class HttpSessionTask implements Runnable { private Socket s; private InputStream iis; private OutputStream oos; private boolean flag=true; public HttpSessionTask(Socket s){ this.s=s; try { iis=s.getInputStream(); oos=s.getOutputStream(); } catch (IOException e) { Utils.printException(e); flag=false; } } //因为http协议是一个无状态的,请求完后回应一次断开 public void run() { if(flag==false){ return; } try { //创建requset对象解析http协议的请求部分 GET /company/index.html HTTP/1.1 //得到资源地址 /kaw/index.html //通过配置文件找到path c:\kaw\index.html //再创建response对象,调用redirect(path); HttpServletRequest request=new HttpServletRequest(iis); String uri=request.getUri(); String filepath=WebProperties.getInstance().getProperty("path")+uri; HttpServletResponse response=new HttpServletResponse(oos); response.redirect(filepath); } catch (IOException e) { // TODO Auto-generated catch block Utils.printException(e); out500(e); }finally{ if(this.s!=null){ try { s.close(); } catch (IOException e) { e.printStackTrace(); } } } } private void out500(Exception e) { //拼接协议输出错误信息 //略 } }
好的,我们只需要在c盘放一个普通的html文件,启动tomcatserver类。
用浏览器访问地址:
网页就被读取出来了,当然这是个很简单的服务器,也只能操作普通文本,后续的学习希望可以深入服务器的学习,多多交流!
版权声明:本文为博主原创文章,未经博主允许不得转载。