黑武士的領地
          ——黑武士是反微軟的JAVA陣營的流氓JAVA程序員
          posts - 26,comments - 4,trackbacks - 0
            HTTP協議簡介

            超文本傳輸協議(HTTP)是位于TCP/IP 協議的應用層,是最廣為人知的協議,也是互連網中最核心的協議之一,同樣,HTTP 也是基于 C/S 或 B/S 模型實現的。事實上,我們使用的瀏覽器如Netscape 或IE 是實現HTTP 協議中的客戶端,而一些常用的Web 服務器軟件如Apache、IIS 和iPlanet Web Server 等是實現HTTP 協議中的服務器端。Web 頁由服務端資源定位,傳輸到瀏覽器,經過瀏覽器的解釋后,被客戶所看到。
            Web 的工作基于客戶機/服務器計算模型,由Web 瀏覽器(客戶機)和Web服務器(服務器)構成,兩者之間采用超文本傳送協議(HTTP)進行通信。HTTP協議是Web瀏覽器和Web服務器之間的應用層協議,是通用的、無狀態的、面向對象的協議。

            一個完整的HTTP協議會話過程包括四個步驟:

            ◆ 連接,Web瀏覽器與Web服務器建立連接,打開一個稱為Socket(套接字)的虛擬文件,此文件的建立標志著連接建立成功;

            ◆ 請求,Web瀏覽器通過Socket向Web服務器提交請求。HTTP的請求一般是GET或POST命令(POST用于FORM參數的傳遞);

            ◆ 應答,Web瀏覽器提交請求后,通過HTTP協議傳送給Web服務器。Web服務器接到后,進行事務處理,處理結果又通過HTTP傳回給Web瀏覽器,從而在Web瀏覽器上顯示出所請求的頁面;

            ◆ 關閉連接,應答結束后Web瀏覽器與Web服務器必須斷開,以保證其它Web瀏覽器能夠與Web服務器建立連接。
            編程思路

            根據上述HTTP協議的會話過程,本實例中實現了GET請求的Web服務器程序的方法,方法如下:

            通過創建ServerSocket 類對象,偵聽用戶指定的端口(為8080),等待并接受客戶機請求到端口。創建與Socket相關聯的輸入流和輸出流,然后讀取客戶機的請求信息。若請求類型是GET,則從請求信息中獲取所訪問的HTML 文件名;如果HTML 文件存在,則打開HTML 文件,把HTTP 頭信息和HTML 文件內容通過Socket 傳回給Web瀏覽器,然后關閉文件,否則發送錯誤信息給Web 瀏覽器。最后關閉與相應Web 瀏覽器連接的Socket。

            用Java編寫Web服務器httpServer.java文件的源代碼如下:

          //httpServer.java
          import java.net.*;
          import java.io.*;
          import java.util.*;
          import java.lang.*;
          public class httpServer{
          public static void main(String args[]) {
          int port;
          ServerSocket server_socket;
          //讀取服務器端口號
          try {
          port = Integer.parseInt(args[0]);
          }
          catch (Exception e) {
          port = 8080;
          }
          try {
          //監聽服務器端口,等待連接請求
          server_socket = new ServerSocket(port);
          System.out.println("httpServer running on port " +
          server_socket.getLocalPort());
          //顯示啟動信息
          while(true) {
          Socket socket = server_socket.accept();
          System.out.println("New connection accepted " +
          socket.getInetAddress() +
          ":" + socket.getPort());
          //創建分線程
          try {
          httpRequestHandler request =
          new httpRequestHandler(socket);
          Thread thread = new Thread(request);
          //啟動線程
          thread.start();
          }
          catch(Exception e) {
          System.out.println(e);
          }
          }
          }
          catch (IOException e) {
          System.out.println(e);
          }
          }
          }
          class httpRequestHandler implements Runnable
          {
          final static String CRLF = "\r\n";
          Socket socket;
          InputStream input;
          OutputStream output;
          BufferedReader br;
          // 構造方法
          public httpRequestHandler(Socket socket) throws Exception
          {
          this.socket = socket;
          this.input = socket.getInputStream();
          this.output = socket.getOutputStream();
          this.br =
          new BufferedReader(new InputStreamReader(socket.getInputStream()));
          }
          // 實現Runnable 接口的run()方法
          public void run()
          {
          try {
          processRequest();
          }
          catch(Exception e) {
          System.out.println(e);
          }
          }
          private void processRequest() throws Exception
          {
          while(true) {
          //讀取并顯示Web 瀏覽器提交的請求信息
          String headerLine = br.readLine();
          System.out.println("The client request is "+headerLine);
          if(headerLine.equals(CRLF) || headerLine.equals("")) break;
          StringTokenizer s = new StringTokenizer(headerLine);
          String temp = s.nextToken();
          if(temp.equals("GET")) {
          String fileName = s.nextToken();
          fileName = "." + fileName ;
          // 打開所請求的文件
          FileInputStream fis = null ;
          boolean fileExists = true ;
          try
          {
          fis = new FileInputStream( fileName ) ;
          }
          catch ( FileNotFoundException e )
          {
          fileExists = false ;
          }
          // 完成回應消息
          String serverLine = "Server: a simple java httpServer";
          String statusLine = null;
          String contentTypeLine = null;
          String entityBody = null;
          String contentLengthLine = "error";
          if ( fileExists )
          {
          statusLine = "HTTP/1.0 200 OK" + CRLF ;
          contentTypeLine = "Content-type: " +
          contentType( fileName ) + CRLF ;
          contentLengthLine = "Content-Length: "
          + (new Integer(fis.available())).toString()
          + CRLF;
          }
          else
          {
          statusLine = "HTTP/1.0 404 Not Found" + CRLF ;
          contentTypeLine = "text/html" ;
          entityBody = "<HTML>" +
          "<HEAD><TITLE>404 Not Found</TITLE></HEAD>" +
          "<BODY>404 Not Found"
          +"<br>usage:http://yourHostName:port/"
          +"fileName.html</BODY></HTML>" ;
          }
          // 發送到服務器信息
          output.write(statusLine.getBytes());
          output.write(serverLine.getBytes());
          output.write(contentTypeLine.getBytes());
          output.write(contentLengthLine.getBytes());
          output.write(CRLF.getBytes());
          // 發送信息內容
          if (fileExists)
          {
          sendBytes(fis, output) ;
          fis.close();
          }
          else
          {
          output.write(entityBody.getBytes());
          }
          }
          }
          //關閉套接字和流
          try {
          output.close();
          br.close();
          socket.close();
          }
          catch(Exception e) {}
          }
          private static void sendBytes(FileInputStream fis, OutputStream os)
          throws Exception
          {
          // 創建一個 1K buffer
          byte[] buffer = new byte[1024] ;
          int bytes = 0 ;
          // 將文件輸出到套接字輸出流中
          while ((bytes = fis.read(buffer)) != -1 )
          {
          os.write(buffer, 0, bytes);
          }
          }
          private static String contentType(String fileName)
          {
          if (fileName.endsWith(".htm") || fileName.endsWith(".html"))
          {
          return "text/html";
          }

          return "fileName";
          }
          }

           


            編程技巧說明

            ◆ 主線程設計

            主線程的設計就是在主線程httpServer 類中實現了服務器端口的偵聽,服務器接受一個客戶端請求之后創建一個線程實例處理請求,代碼如下:

          import java.net.*;
          import java.io.*;
          import java.util.*;
          import java.lang.*;
          public class httpServer{
          public static void main(String args[]) {
          port;
          ServerSocket server_socket;
          //讀取服務器端口號
          try {
          port = Integer.parseInt(args[0]);
          }
          catch (Exception e) {
          port = 8080;
          }
          try {
          //監聽服務器端口,等待連接請求
          server_socket = new ServerSocket(port);
          System.out.println("httpServer running on port "
          +server_socket.getLocalPort());
          ..........
          ..........

            ◆ 連接處理分線程設計

            在分線程httpRequestHandler 類中實現了HTTP 協議的處理,這個類實現了Runnable 接口,代碼如下:

          class httpRequestHandler implements Runnable
          {
          final static String CRLF = "\r\n";
          Socket socket;
          InputStream input;
          OutputStream output;
          BufferedReader br;
          // 構造方法
          public httpRequestHandler(Socket socket) throws Exception
          {
          this.socket = socket;
          //得到輸入輸出流
          this.input = socket.getInputStream();
          this.output = socket.getOutputStream();
          this.br =
          new BufferedReader(new InputStreamReader(socket.getInputStream()));
          }

          // 實現Runnable 接口的run()方法
          public void run()
          {
          try {
          processRequest();
          }
          catch(Exception e) {
          System.out.println(e);
          }
          }

            ◆ 構建processRequest()方法來處理信息的接收和發送

            作為實現Runnable 接口的主要內容,在run()方法中調用processRequest()方法來處理客戶請求內容的接收和服務器返回信息的發送,代碼如下:

          private void processRequest() throws Exception
          {
          while(true) {
          //讀取并顯示Web 瀏覽器提交的請求信息
          String headerLine = br.readLine();
          System.out.println("The client request is "+ headerLine);
          if(headerLine.equals(CRLF) || headerLine.equals("")) break;
          //根據請求字符串中的空格拆分客戶請求
          StringTokenizer s = new StringTokenizer(headerLine);
          String temp = s.nextToken();
          if(temp.equals("GET")) {
          String fileName = s.nextToken();
          fileName = "." + fileName ;
          .............
          .............

            在processRequest()方法中得到客戶端請求后,利用一個StringTokenizer 類完成了字符串的拆分,這個類可以實現根據字符串中指定的分隔符(缺省為空格)將字符串拆分成為字串的功能。利用nextToken()方法依次得到這些字串;sendBytes()方法完成信息內容的發送,contentType()方法用于判斷文件的類型。

            顯示Web頁面

            顯示 Web 頁面的index.html 文件代碼如下:

          <html>
          <head>
          <meta http-equiv="Content-Language" content="zh-cn">
          <meta name="GENERATOR" content="Microsoft FrontPage 5.0">
          <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
          <title>Java Web 服務器</title>
          </head>
          <body>
          <p>********* <font color="#FF0000">歡迎你的到來!</font>*********</p>
          <p>這是一個用 Java 語言實現的 Web 服務器</p>
          <hr>
          </body>
          </html>

            運行實例

            為了測試上述程序的正確性,將編譯后的httpServer.class、httpRequestHandler.class和上面的index.html文件置于網絡的某臺主機的同一目錄中。

            首先運行服務器程序 java httpServer 8080,服務器程序運行后顯示端口信息“httpServer runing on port 8080”, 然后在瀏覽器的地址欄中輸入http://localhost:8080/index.html,就可以正確顯示網頁,同時在顯示“httpServer runing on port 8080 ”窗口中服務器會出現一些信息。

          posted on 2005-08-06 09:39 黑武士 閱讀(243) 評論(0)  編輯  收藏 所屬分類: JAVA技術
          主站蜘蛛池模板: 介休市| 西城区| 东乌| 云和县| 枣庄市| 图木舒克市| 财经| 深州市| 浠水县| 盈江县| 五台县| 章丘市| 蒙城县| 盘山县| 扎赉特旗| 中超| 宜黄县| 高唐县| 曲沃县| 温泉县| 化州市| 万载县| 石河子市| 吉首市| 含山县| 肃南| 武平县| 黔南| 武穴市| 青铜峡市| 福州市| 南川市| 深州市| 云霄县| 崇义县| 西峡县| 广宁县| 洛隆县| 保山市| 共和县| 当雄县|