zoukankan      html  css  js  c++  java
  • how tomcat works 读书笔记(一)----------一个简单的webserver


    http协议

    若是两个人能正常的说话交流,那么他们间必然有一套统一的语言规则<在网络上server与client能交流也依赖与一套规则,它就是我们说的http规则(超文本传输协议Hypertext transfer protocol)。


    http分两部分,一个是请求(client发给server),一个是回复(server发给client)。
    先看http请求 

    以下就是一个http请求的样例,当中的各项參数,请查阅相关文档。(http://www.cnblogs.com/yin-jingyu/archive/2011/08/01/2123548.html)



    http回复

    以下就是http回复的样例,除了这个图之外,后面的部分就是大家看到的页面的源码


    socket

    我们一般说的socket,广义上包括java.net包下的Socket类与ServerSocekt类。
    还有一方面有基于tcp的网络编程也有基于udp的网络编程,当中区别大家百度,这里仅仅谈tcp。
    定义性的东西大家能够查看各种资料(个人推荐尚学堂 马士兵老师解说的socket部分视频,但在看socket之前建议大家先看io部分),带大家看一段代码,大家应该就会知道socket编程的大致原理了。(代码来自马士兵老师的讲义)


    import java.net.*;
    import java.io.*;
    
    
    public class TCPServer {
    	public static void main(String[] args) throws Exception {
    		ServerSocket ss = new ServerSocket(6666);      //在本机的TCP6666号端口上监听
    		while(true) {
    			Socket s = ss.accept();                //ServerSocket的accept为堵塞式方法,仅仅有当它监听到一个请求时
    			                                       //它才会运行
                            System.out.println("a client connect!");
    			DataInputStream dis = new DataInputStream(s.getInputStream());//获得客户端向自己说的"话"
    			                                       //InputStream 从外部指向内存
    			System.out.println(dis.readUTF());     //依照uft-8的格式读取内容
    			dis.close();
    			s.close();
    		}
    		
    	}
    }
    
    
    import java.net.*;
    import java.io.*;
    
    
    public class TCPClient {
    	public static void main(String[] args) throws Exception {
    		Socket s = new Socket("127.0.0.1", 6666);       //连接127.0.0.1(本机)的tcp端口6666
    		OutputStream os = s.getOutputStream();          //获得一条线路,来给服务器"说话"
    		DataOutputStream dos = new DataOutputStream(os);//对这个线路进行包装
    		Thread.sleep(3000);                             //"暂停"3秒
    		dos.writeUTF("hello server!");                  //对服务器说 hello server! 
    		dos.flush();
    		dos.close();
    		s.close();
    	}
    }


    先执行server端,再执行client端。当执行client端后,控制台首先会打印a client connect!三秒之后会打印hello server! 

    模拟一个最最最基础的tomcat

    import java.net.Socket;
    import java.net.ServerSocket;
    import java.net.InetAddress;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.io.IOException;
    import java.io.File;
    
    
    public class HttpServer {
    
    
      /** WEB_ROOT is the directory where our HTML and other files reside.
       *  For this package, WEB_ROOT is the "webroot" directory under the working
       *  directory.
       *  The working directory is the location in the file system
       *  from where the java command was invoked.
       */
      public static final String WEB_ROOT =
        System.getProperty("user.dir") + File.separator  + "webroot";
    
    
      // shutdown command
      private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
    
    
      // the shutdown command received
      private boolean shutdown = false;
    
    
      public static void main(String[] args) {
        HttpServer server = new HttpServer();
        server.await();
      }
    
    
      public void await() {
        ServerSocket serverSocket = null;
        int port = 8080;
        try {
          serverSocket =  new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));  
                    //这个1是什么功能 參加 http://www.51cto.com/art/200702/40196_1.htm
        }
        catch (IOException e) {
          e.printStackTrace();
          System.exit(1);
        }
    
    
        // Loop waiting for a request
        while (!shutdown) {  //最開始的时候 shutdown为false 这段话会执行
          Socket socket = null;
          InputStream input = null;
          OutputStream output = null;
          try {
            socket = serverSocket.accept();   //仅仅有当有client请求时 它才会执行 堵塞式方法!
            System.out.println(new Date()+"AAAAAAAAAAAA");
            input = socket.getInputStream();  //里面放的是client对server说的话
            output = socket.getOutputStream();//这里面将要放的是server要对client说的话
    
    
            // create Request object and parse
            Request request = new Request(input);
            request.parse();                  //參见request
    
    
            // create Response object
            Response response = new Response(output);
            response.setRequest(request);
            response.sendStaticResource();
    
    
            // Close the socket
            socket.close();
    
    
            //check if the previous URI is a shutdown command
            shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
          }
          catch (Exception e) {
            e.printStackTrace();
            continue;
          }
        }
      }
    }
    




    import java.io.InputStream;
    import java.io.IOException;
    
    
    public class Request {
    
    
      private InputStream input;
      private String uri;
    
    
      public Request(InputStream input) {
        this.input = input;
      }
    
    
      public void parse() {
        // Read a set of characters from the socket
        StringBuffer request = new StringBuffer(2048);
        int i;
        byte[] buffer = new byte[2048];
        try {
          i = input.read(buffer);          
        }
        catch (IOException e) {
          e.printStackTrace();
          i = -1;
        }
        for (int j=0; j<i; j++) {
          request.append((char) buffer[j]);   //将client的请求加到request(StringBuffer)中
        }
        System.out.println("request 例如以下");
        System.out.print(request.toString());
        uri = parseUri(request.toString());
        System.out.println("uri 例如以下  "+uri);
      }
    
    
      /**
      *看看System.out.println("uri 例如以下  "+uri); 就不用解释这种方法了
      *
      **/
      private String parseUri(String requestString) {
        int index1, index2;
        index1 = requestString.indexOf(' ');
        if (index1 != -1) {
          index2 = requestString.indexOf(' ', index1 + 1);
          if (index2 。

    index1) return requestString.substring(index1 + 1, index2); } return null; } public String getUri() { return uri; } }





    import java.io.OutputStream;
    import java.io.IOException;
    import java.io.FileInputStream;
    import java.io.File;
    
    
    /*
      HTTP Response = Status-Line
        *(( general-header | response-header | entity-header ) CRLF)
        CRLF
        [ message-body ]
        Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
    */
    
    
    public class Response {
    
    
      private static final int BUFFER_SIZE = 1024;
      Request request;
      OutputStream output;
    
    
      public Response(OutputStream output) {
        this.output = output;
      }
    
    
      public void setRequest(Request request) {
        this.request = request;
      }
    
    
      public void sendStaticResource() throws IOException {
        byte[] bytes = new byte[BUFFER_SIZE];
        FileInputStream fis = null;
        try {
          System.out.println(HttpServer.WEB_ROOT+"  **** "+request.getUri());
          File file = new File(HttpServer.WEB_ROOT, request.getUri());   //连接用户请求的"文件"
          if (file.exists()) {
            fis = new FileInputStream(file);
            int ch = fis.read(bytes, 0, BUFFER_SIZE);       //把文件中的东西读出来放到bytes字符数组里
            while (ch!=-1) {                                //把bytes数组里的东西放到要给client回复的流里面
              output.write(bytes, 0, ch);
              ch = fis.read(bytes, 0, BUFFER_SIZE);
            }
          }
          else {                                            //要是文件不存在  不解释
            // file not found
            String errorMessage = "HTTP/1.1 404 File Not Found
    " +
              "Content-Type: text/html
    " +
              "Content-Length: 23
    " +
              "
    " +
              "<h1。File Not Found</h1。";
            output.write(errorMessage.getBytes());
          }
        }
        catch (Exception e) {
          // thrown if cannot instantiate a File object
          System.out.println(e.toString() );
        }
        finally {
          if (fis!=null)
            fis.close();
        }
      }
    }


    首先假设大家用的是Eclipse,那么没有不论什么问题,假设大家是用命令行的形式的话会存在一个问题,HttpServer与Response两个类相互依赖,先编译谁?
    解决的方法 cd到三个类的文件夹 然后 javac *.java


    等启动HttpServer后
    在浏览器输入localhost:8080/index.html

    显演示样例如以下 



    明确了吧 我们把index.html放到D:尚学堂 j2eejavase尚学堂科技_马士兵_J2SE_5.0_第01章_JAVA简单介绍_源码_及重要说明javaSocket oWebContent 文件夹下



    index.html内容例如以下
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
    我是index
    </body>
    </html>

    再次请求 截图例如以下




    大家一定非常奇怪,我为什么不用火狐或这个Chrome,找个EditPlus点过来点过去。
    大家试试就知道了,火狐不知道由于什么原因,在地址栏敲回车后,会发出两次请求。

    结果就是报错。




    再试试http://localhost:8080/SHUTDOWN


    程序退出


  • 相关阅读:
    Java安全之对称加密、非对称加密、数字签名
    Java 设计模式 之 中介者模式(Mediator)
    使用jquery获取radio的值
    java6枚举类型
    java http头信息
    怎样用java生成GUID与UUID
    struts2国际化
    JSON.stringify(),JSON.parse(),toJSON()方法使用
    阻塞队列之六:LinkedBlockingDeque
    jQuery给控件赋值....
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5256067.html
Copyright © 2011-2022 走看看