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

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

            一個(gè)完整的HTTP協(xié)議會(huì)話過(guò)程包括四個(gè)步驟:

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

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

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

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

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

            通過(guò)創(chuàng)建ServerSocket 類對(duì)象,偵聽(tīng)用戶指定的端口(為8080),等待并接受客戶機(jī)請(qǐng)求到端口。創(chuàng)建與Socket相關(guān)聯(lián)的輸入流和輸出流,然后讀取客戶機(jī)的請(qǐng)求信息。若請(qǐng)求類型是GET,則從請(qǐng)求信息中獲取所訪問(wèn)的HTML 文件名;如果HTML 文件存在,則打開(kāi)HTML 文件,把HTTP 頭信息和HTML 文件內(nèi)容通過(guò)Socket 傳回給Web瀏覽器,然后關(guān)閉文件,否則發(fā)送錯(cuò)誤信息給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ù)器端口號(hào)
          try {
          port = Integer.parseInt(args[0]);
          }
          catch (Exception e) {
          port = 8080;
          }
          try {
          //監(jiān)聽(tīng)服務(wù)器端口,等待連接請(qǐng)求
          server_socket = new ServerSocket(port);
          System.out.println("httpServer running on port " +
          server_socket.getLocalPort());
          //顯示啟動(dòng)信息
          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);
          //啟動(dòng)線程
          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()));
          }
          // 實(shí)現(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 瀏覽器提交的請(qǐng)求信息
          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 ;
          // 打開(kāi)所請(qǐng)求的文件
          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)建一個(gè) 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";
          }
          }

           


            編程技巧說(shuō)明

            ◆ 主線程設(shè)計(jì)

            主線程的設(shè)計(jì)就是在主線程httpServer 類中實(shí)現(xiàn)了服務(wù)器端口的偵聽(tīng),服務(wù)器接受一個(gè)客戶端請(qǐng)求之后創(chuàng)建一個(gè)線程實(shí)例處理請(qǐ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ù)器端口號(hào)
          try {
          port = Integer.parseInt(args[0]);
          }
          catch (Exception e) {
          port = 8080;
          }
          try {
          //監(jiān)聽(tīng)服務(wù)器端口,等待連接請(qǐng)求
          server_socket = new ServerSocket(port);
          System.out.println("httpServer running on port "
          +server_socket.getLocalPort());
          ..........
          ..........

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

            在分線程httpRequestHandler 類中實(shí)現(xiàn)了HTTP 協(xié)議的處理,這個(gè)類實(shí)現(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()));
          }

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

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

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

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

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

            顯示W(wǎng)eb頁(yè)面

            顯示 Web 頁(yè)面的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">歡迎你的到來(lái)!</font>*********</p>
          <p>這是一個(gè)用 Java 語(yǔ)言實(shí)現(xiàn)的 Web 服務(wù)器</p>
          <hr>
          </body>
          </html>

            運(yùn)行實(shí)例

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

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

          posted on 2005-08-06 09:39 黑武士 閱讀(241) 評(píng)論(0)  編輯  收藏 所屬分類: JAVA技術(shù)
          主站蜘蛛池模板: 江都市| 沙田区| 满洲里市| 驻马店市| 徐闻县| 黑河市| 大竹县| 洛阳市| 常熟市| 修武县| 元氏县| 嘉善县| 江山市| 灵璧县| 扎赉特旗| 柳河县| 调兵山市| 锡林浩特市| 什邡市| 揭东县| 舞钢市| 公主岭市| 常州市| 新晃| 张家界市| 临邑县| 锦州市| 西吉县| 赣州市| 新营市| 正安县| 绥棱县| 盐津县| 绥化市| 锦屏县| 正宁县| 满城县| 铁力市| 文登市| 泸水县| 梁河县|