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

            超文本傳輸協(xié)議(HTTP)是位于TCP/IP 協(xié)議的應(yīng)用層,是最廣為人知的協(xié)議,也是互連網(wǎng)中最核心的協(xié)議之一,同樣,HTTP 也是基于 C/S 或 B/S 模型實現(xiàn)的。事實上,我們使用的瀏覽器如Netscape 或IE 是實現(xiàn)HTTP 協(xié)議中的客戶端,而一些常用的Web 服務(wù)器軟件如Apache、IIS 和iPlanet Web Server 等是實現(xiàn)HTTP 協(xié)議中的服務(wù)器端。Web 頁由服務(wù)端資源定位,傳輸?shù)綖g覽器,經(jīng)過瀏覽器的解釋后,被客戶所看到。
            Web 的工作基于客戶機(jī)/服務(wù)器計算模型,由Web 瀏覽器(客戶機(jī))和Web服務(wù)器(服務(wù)器)構(gòu)成,兩者之間采用超文本傳送協(xié)議(HTTP)進(jìn)行通信。HTTP協(xié)議是Web瀏覽器和Web服務(wù)器之間的應(yīng)用層協(xié)議,是通用的、無狀態(tài)的、面向?qū)ο蟮膮f(xié)議。

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

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

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

            ◆ 應(yīng)答,Web瀏覽器提交請求后,通過HTTP協(xié)議傳送給Web服務(wù)器。Web服務(wù)器接到后,進(jìn)行事務(wù)處理,處理結(jié)果又通過HTTP傳回給Web瀏覽器,從而在Web瀏覽器上顯示出所請求的頁面;

            ◆ 關(guān)閉連接,應(yīng)答結(jié)束后Web瀏覽器與Web服務(wù)器必須斷開,以保證其它Web瀏覽器能夠與Web服務(wù)器建立連接。
            編程思路

            根據(jù)上述HTTP協(xié)議的會話過程,本實例中實現(xiàn)了GET請求的Web服務(wù)器程序的方法,方法如下:

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

            用Java編寫Web服務(wù)器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;
          //讀取服務(wù)器端口號
          try {
          port = Integer.parseInt(args[0]);
          }
          catch (Exception e) {
          port = 8080;
          }
          try {
          //監(jiān)聽服務(wù)器端口,等待連接請求
          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());
          //創(chuàng)建分線程
          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;
          // 構(gòu)造方法
          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()));
          }
          // 實現(xiàn)Runnable 接口的run()方法
          public void run()
          {
          try {
          processRequest();
          }
          catch(Exception e) {
          System.out.println(e);
          }
          }
          private void processRequest() throws Exception
          {
          while(true) {
          //讀取并顯示W(wǎng)eb 瀏覽器提交的請求信息
          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 ;
          }
          // 完成回應(yīng)消息
          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>" ;
          }
          // 發(fā)送到服務(wù)器信息
          output.write(statusLine.getBytes());
          output.write(serverLine.getBytes());
          output.write(contentTypeLine.getBytes());
          output.write(contentLengthLine.getBytes());
          output.write(CRLF.getBytes());
          // 發(fā)送信息內(nèi)容
          if (fileExists)
          {
          sendBytes(fis, output) ;
          fis.close();
          }
          else
          {
          output.write(entityBody.getBytes());
          }
          }
          }
          //關(guān)閉套接字和流
          try {
          output.close();
          br.close();
          socket.close();
          }
          catch(Exception e) {}
          }
          private static void sendBytes(FileInputStream fis, OutputStream os)
          throws Exception
          {
          // 創(chuàng)建一個 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";
          }
          }

           


            編程技巧說明

            ◆ 主線程設(shè)計

            主線程的設(shè)計就是在主線程httpServer 類中實現(xiàn)了服務(wù)器端口的偵聽,服務(wù)器接受一個客戶端請求之后創(chuàng)建一個線程實例處理請求,代碼如下:

          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;
          //讀取服務(wù)器端口號
          try {
          port = Integer.parseInt(args[0]);
          }
          catch (Exception e) {
          port = 8080;
          }
          try {
          //監(jiān)聽服務(wù)器端口,等待連接請求
          server_socket = new ServerSocket(port);
          System.out.println("httpServer running on port "
          +server_socket.getLocalPort());
          ..........
          ..........

            ◆ 連接處理分線程設(shè)計

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

          class httpRequestHandler implements Runnable
          {
          final static String CRLF = "\r\n";
          Socket socket;
          InputStream input;
          OutputStream output;
          BufferedReader br;
          // 構(gòu)造方法
          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()));
          }

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

            ◆ 構(gòu)建processRequest()方法來處理信息的接收和發(fā)送

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

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

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

            顯示W(wǎng)eb頁面

            顯示 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 服務(wù)器</title>
          </head>
          <body>
          <p>********* <font color="#FF0000">歡迎你的到來!</font>*********</p>
          <p>這是一個用 Java 語言實現(xiàn)的 Web 服務(wù)器</p>
          <hr>
          </body>
          </html>

            運行實例

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

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

          posted on 2005-08-06 09:39 黑武士 閱讀(243) 評論(0)  編輯  收藏 所屬分類: JAVA技術(shù)
          主站蜘蛛池模板: 西乡县| 石阡县| 永吉县| 彭泽县| 星子县| 巴楚县| 原阳县| 玉树县| 如东县| 舒兰市| 临湘市| 桃源县| 曲水县| 长治县| 涞水县| 土默特左旗| 股票| 邵武市| 松阳县| 论坛| 丰宁| 马尔康县| 罗平县| 凌云县| 怀远县| 安塞县| 普格县| 南京市| 大埔区| 岳阳市| 泾源县| 天长市| 萨迦县| 准格尔旗| 合水县| 呼图壁县| 富裕县| 通许县| 西吉县| 都安| 关岭|