Http请求、Http响应、 Socket

转自http://uule.iteye.com/blog/2188813。感觉很有用。


(一)Http请求、Http响应、 Socket


第一章:一个简单(一)Http请求、Http响应、 Socket的Web服务器

    本章说明java web服务器是如何工作的。Web服务器也成为超文本传输协议(HTTP)服务器,因为它使用HTTP来跟客户端进行通信的,这通常是个web浏览器。

一个基于java的web服务器使用两个重要的类:java.net.Socket和java.net.ServerSocket,并通过HTTP消息进行通信。因此这章就自然是从HTTP和这两个类的讨论开始的。接下去,解释这章附带的一个简单的web服务器。

 

1.1超文本传输协议(HTTP)

    HTTP是一种协议,允许web服务器和浏览器通过互联网进行来发送和接受数据。它是一种请求和响应协议。客户端请求一个文件而服务器响应请求。HTTP使用可靠的TCP连接--TCP默认使用80端口。第一个HTTP版是HTTP/0.9,然后被HTTP/1.0所替代。正在取代HTTP/1.0的是当前版本HTTP/1.1,它定义于征求意见文档(RFC) 2616,可以从http://www.w3.org/Protocols/HTTP/1.1/rfc2616.pdf下载。

    注意:本节涵盖的HTTP 1.1只是简略的帮助你理解web服务器应用发送的消息。假如你对更多详细信息感兴趣,请阅读RFC 2616。

    在HTTP中,始终都是客户端通过建立连接和发送一个HTTP请求从而开启一个事务。web服务器不需要联系客户端或者对客户端做一个回调连接。无论是客户端或者服务器都可以提前终止连接。举例来说,当你正在使用一个web浏览器的时候,可以通过点击浏览器上的停止按钮来停止一个文件的下载进程,从而有效的关闭与web服务器的HTTP连接。

 

1.2HTTP请求                                     

    一个HTTP请求包括三个组成部分:

·  方法 — 统一资源标识符(URI) — 协议/版本

·  请求的头部

·  主体内容

 

    下面是一个HTTP请求的例子:

Java代码   收藏代码
  1. POST /examples/default.jsp HTTP/1.1  
  2. Accept: text/plain; text/html  
  3. Accept-Language: en-gb  
  4. Connection: Keep-Alive  
  5. Host: localhost  
  6. User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)  
  7. Content-Length: 33  
  8. Content-Type: application/x-www-form-urlencoded  
  9. Accept-Encoding: gzip, deflate  
  10.   
  11. lastName=Franks&firstName=Michael  

 

    方法—统一资源标识符(URI)—协议/版本出现在请求的第一行。

POST /examples/default.jsp HTTP/1.1

    这里POST是请求方法,/examples/default.jsp是URI,而HTTP/1.1是协议/版本部分。

 

每个HTTP请求可以使用HTTP标准里边提到的多种方法之一。HTTP 1.1支持7种类型的请求:GET, POST,HEAD, OPTIONS, PUT, DELETE和TRACE。

GET和POST在互联网应用里边最普遍使用的。

URI完全指明了一个互联网资源。URI通常是相对服务器的根目录解释的。因此,始终一斜线/开头。统一资源定位器(URL)其实是一种URI(查看http://www.ietf.org/rfc/rfc2396.txt)来的。该协议版本代表了正在使用的HTTP协议的版本。

请求的头部包含了关于客户端环境和请求的主体内容的有用信息。例如它可能包括浏览器设置的语言,主体内容的长度等等。每个头部通过一个回车换行符(CRLF)来分隔的。

对于HTTP请求格式来说,头部和主体内容之间有一个回车换行符(CRLF)是相当重要的。CRLF告诉HTTP服务器主体内容是在什么地方开始的。在一些互联网编程书籍中,CRLF还被认为是HTTP请求的第四部分。

 

在前面一个HTTP请求中,主体内容只不过是下面一行:

lastName=Franks&firstName=Michael

    实体内容在一个典型的HTTP请求中可以很容易的变得更长。

 

1.3 HTTP Response

 

与HTTP Request类似,HTTP Response也由三部分组成:

    协议-状态-描述

Response 头

Response 体

 

举例如下: 

Html代码   收藏代码
  1. HTTP/1.1 200 OK    
  2. Server: Microsoft-IIS/4.0    
  3. Date: Mon, 5 Jan 2004 13:13:33 GMT  Content-Type: text/html    
  4. Last-Modified: Mon, 5 Jan 2004 13:13:12 GMT  Content-Length: 112      
  5. <html>  
  6.     <head>    
  7.         <title>HTTP Response Example</title>  
  8.     </head>  
  9. <body>  Welcome to Brainy Software  </body>  
  10. </html>   

   

注意响应实体(entity)与响应头(header)之间有一个空白行(CRLF)。

 

1.4   Socket 类

套接字socket代表客户端与服务器连接,你可以通过他与服务器建立连接,可以指定host和port,Java中用Socket类来建立,有多个构造函数。

 

可以通过ServerSocket建立http服务器或者ftp服务器。

 

socket 通信的实例代码如下:

Java代码   收藏代码
  1. Socket socket = new Socket("127.0.0.1""8080");    //建立连接  
  2.   OutputStream os = socket.getOutputStream();   //获取输出流  
  3.   boolean autoflush = true;   
  4.   PrintWriter out = new PrintWriter(   
  5.         socket.getOutputStream(), autoflush);   //设置自动flush  
  6.   BufferedReader in = new BufferedReader(   
  7.         new InputStreamReader( socket.getInputstream() ));   
  8.    
  9.   // send an HTTP request to the web server   
  10.   out.println("GET /index.jsp HTTP/1.1");       //拼装HTTP请求信息  
  11.   out.println("Host: localhost:8080");   
  12.    
  13.   out.println("Connection: Close");   
  14.   out.println();   
  15.    
  16.   // read the response   
  17.   boolean loop = true;   
  18.   StringBuffer sb = new StringBuffer(8096);   
  19.   while (loop) {   
  20.     if ( in.ready() ) {   
  21.       int i=0;  
  22.        while (i!=-1) {   
  23.         i = in.read();   
  24.         sb.append((char) i);   
  25.       }   
  26.       loop = false;   
  27.     }   
  28.     Thread.currentThread().sleep(50);   //由于是阻塞写入,暂停50ms,保证可以写入。  
  29.   }   
  30.    
  31.   // display the response to the out console   
  32.   System.out.println(sb.toString());   
  33.   socket.close();  

   

1.5   ServerSocket 类

Socket类表示一个客户端socket,相应的ServerSocket类表示了一个服务器端应用。服务器端socket需要等待来自客户端的连接请求。一旦ServerSocket接收到来自客户端的连接请求,它会实例化一个Socket类的对象来处理与客户端的通信。

 

1.6  应用举例

该程序包括三个部分,HttpServer、Request和Response。该程序只能发送静态资源,如HTML文件,图片文件,但不会发送响应头信息。

代码文件如下:

 

Java代码   收藏代码
  1. package ex01.pyrmont;   
  2.    
  3. import java.net.Socket;   
  4. import java.net.ServerSocket;   
  5. import java.net.InetAddress;   
  6. import java.io.InputStream;   
  7. import java.io.OutputStream;   
  8. import java.io.IOException;   
  9. import java.io.File;   
  10.    
  11. public class HttpServer {   
  12.    
  13.     /** WEB_ROOT is the directory where our HTML and other files reside.  
  14.     *  For this package, WEB_ROOT is the "webroot" directory under the  
  15.     *  working directory.  
  16.     *  The working directory is the location in the file system  
  17.     *  from where the java command was invoked.  
  18.     */   
  19.     public static final String WEB_ROOT =   
  20.     System.getProperty("user.dir") + File.separator  + "webroot";   
  21.   
  22.     // shutdown command   
  23.     private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";   
  24.   
  25.     // the shutdown command received   
  26.     private boolean shutdown = false;   
  27.   
  28.     public static void main(String[] args) {   
  29.         HttpServer server = new HttpServer();    
  30.         server.await();   
  31.     }   
  32.    
  33.     public void await() {   
  34.       ServerSocket serverSocket = null;   
  35.       int port = 8080;   
  36.       try {   
  37.         serverSocket =  new ServerSocket(port, 1,   
  38.             InetAddress.getByName("127.0.0.1"));   
  39.       }   
  40.       catch (IOException e) {   
  41.         e.printStackTrace();   
  42.         System.exit(1);   
  43.       }   
  44.       // Loop waiting for a request   
  45.       while (!shutdown) {   
  46.         Socket socket = null;   
  47.         InputStream input = null;   
  48.         OutputStream output = null;   
  49.        
  50.         try {   
  51.           socket = serverSocket.accept();   
  52.           input = socket.getInputStream();   
  53.           output = socket.getOutputStream();   
  54.             
  55.           // create Request object and parse   
  56.           Request request = new Request(input);   
  57.           request.parse();   
  58.        
  59.           // create Response object   
  60.           Response response = new Response(output);   
  61.           response.setRequest(request);   
  62.           response.sendStaticResource();   
  63.        
  64.           // Close the socket   
  65.           socket.close();    
  66.           //check if the previous URI is a shutdown command   
  67.           shutdown = request.getUri().equals(SHUTDOWN_COMMAND);   
  68.         }   
  69.         catch (Exception e) {   
  70.           e.printStackTrace ();   
  71.           continue;   
  72.         }   
  73.       }   
  74.     }     
  75. }   

 

Java代码   收藏代码
  1. package ex01.pyrmont;   
  2.    
  3. import java.io.InputStream;   
  4. import java.io.IOException;   
  5.    
  6. public class Request {   
  7.    private InputStream input;   
  8.    private String uri;   
  9.    
  10.    public Request(InputStream input) {   
  11.      this.input = input;   
  12.    }   
  13.    
  14.     public void parse() {   
  15.        // Read a set of characters from the socket   
  16.        StringBuffer request = new StringBuffer(2048);   
  17.        int i;   
  18.        byte[] buffer = new byte[2048];   
  19.        try {   
  20.          i = input.read(buffer);   
  21.        }   
  22.        catch (IOException e) {   
  23.          e.printStackTrace();   
  24.          i = -1;   
  25.        }   
  26.        for (int j=0; j<i; j++) {   
  27.          request.append((char) buffer[j]);   
  28.        }   
  29.        System.out.print(request.toString());   
  30.        uri = parseUri(request.toString());   
  31.     }   
  32.      
  33.    
  34.     private String parseUri(String requestString) {   
  35.        int index1, index2;   
  36.        index1 = requestString.indexOf(' ');   
  37.        if (index1 != -1) {   
  38.          index2 = requestString.indexOf(' ', index1 + 1);   
  39.          if (index2 > index1)   
  40.            return requestString.substring(index1 + 1, index2);   
  41.        }   
  42.        return null;   
  43.     }   
  44.      
  45.    
  46.    public String getUri() {   
  47.      return uri;   
  48.    }   
  49. }  

 

Java代码   收藏代码
  1. package ex01.pyrmont;   
  2.    
  3. import java.io.OutputStream; import java.io.IOException;   
  4. import java.io.FileInputStream;   
  5. import java.io.File;   
  6.    
  7. /*  
  8.    HTTP Response = Status-Line  
  9.      *(( general-header | response-header | entity-header ) CRLF)  
  10.      CRLF  
  11.      [ message-body ]  
  12.      Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF  
  13. */   
  14.    
  15. public class Response {   
  16.    
  17.    private static final int BUFFER_SIZE = 1024;   
  18.    Request request;   
  19.    OutputStream output;   
  20.    
  21.    public Response(OutputStream output) {   
  22.      this.output = output;   
  23.    }   
  24.    
  25.    public void setRequest(Request request) {   
  26.      this.request = request;   
  27.    }   
  28.    
  29.    public void sendStaticResource() throws IOException {   
  30.      byte[] bytes = new byte[BUFFER_SIZE];   
  31.      FileInputStream fis = null;   
  32.      try {   
  33.        File file = new File(HttpServer.WEB_ROOT, request.getUri());   
  34.        if (file.exists()) {   
  35.              fis = new FileInputStream(file);   
  36.              int ch = fis.read(bytes, 0, BUFFER_SIZE);   
  37.              while (ch!=-1) {   
  38.                output.write(bytes, 0, ch);   
  39.                ch = fis.read(bytes, 0, BUFFER_SIZE);   
  40.              }   
  41.        }   
  42.        else {   
  43.             // file not found   
  44.             String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +   
  45.                 "Content-Type: text/html\r\n" +   
  46.                 "Content-Length: 23\r\n" +            "\r\n" +   
  47.        
  48.                 "<h1>File Not Found</h1>";   
  49.             output.write(errorMessage.getBytes());   
  50.        }   
  51.      }   
  52.      catch (Exception e) {   
  53.        // thrown if cannot instantiate a File object   
  54.        System.out.println(e.toString() );   
  55.      }   
  56.      finally {   
  57.        if (fis!=null)   
  58.          fis.close();   
  59.      }   
  60.    }   
  61. }   

 ...

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值