Cyh的博客

          Email:kissyan4916@163.com
          posts - 26, comments - 19, trackbacks - 0, articles - 220

          網絡編程>>HTTP服務器

          Posted on 2009-12-12 16:22 啥都寫點 閱讀(330) 評論(0)  編輯  收藏 所屬分類: J2SE
               與一般的Socket編程一樣,服務器端需要在某個端口上開啟一個ServerSocket,以等待、接受客戶端的請求。
               采用多線程技術,支持多用戶同時訪問,對于每一個請求,都用一個線程專門去處理。
               客戶端發送給服務器端的HTTP請求遵循一定的格式,服務器端需要根據HTTP請求確定請求的類型以及請求的文件名,這些信息都存儲在請求消息的第一行中。比如,用戶瀏覽器地址欄中輸入:" http://localhost:80/test/hehe.htm ",那么產生的請求的第一行便是"GET/test/hehe.htm  HTTP/1.1"         Socket的getInetAddress方法能獲得客戶端的網絡地址信息,包括IP和端口號。
               在給客戶端發送響應消息時,也要按照HTTP協議,給響應消息添加頭信息,然后將被請求文件的字節數組添加到頭信息的后面,頭信息的第一行為為"HTTP/1.1 200 0K" 表示"HTTP協議的版本為1.1,處理請求成功",頭信息的第一行為"HTTP/1.1 400"表示"HTTP協議的版本為1.1,處理請求失敗,文件沒找到"。


          /**
           * HTTP的服務器,接收來自客戶端的HTTP請求。
           * 將要發布的HTML文件放置在工程的根目錄下,
           * 然后在瀏覽器中輸入類似"
          http://localhost:80/"的網址,
           * 將能夠顯示網頁的內容。
           
          */

          public class HttpServer {
              
          // 服務器名和端口
              String serverName;
              
          int serverPort;

              
          // 定義server的名字、版本號、端口 
              public HttpServer(String name, int port) {
                  
          this.serverName = name;
                  
          this.serverPort = port;
              }


              
          public void run() {
                  
          // 顯示名字和端口號 
                  System.out.println("HttpServer: " + serverName + "" + serverPort);
                  
          try {
                      
          // 得到服務器監聽端口 
                      ServerSocket server = new ServerSocket(serverPort);
                      
          do {
                          
          // 等待連接請求 
                          Socket client = server.accept();
                          
          // 為連接請求分配一個線程 
                          (new HTTPServerThread(client)).start();
                      }
           while (true);
                  }
           catch (Exception e) {
                      e.printStackTrace();
                      System.exit(
          1);
                  }

              }

              
          // 構造一個server,并運行 
              public static void main(String args[]) {
                  HttpServer server 
          = new HttpServer("MyHTTPServer"80);
                  server.run();
              }

          }


          /**
           * 處理HTTP請求的線程,一個HTTP請求對應一個線程
           
          */

          class HTTPServerThread extends Thread {
              
          // 服務器與客戶端之間的socket
              Socket client;
              
          public HTTPServerThread(Socket client) {
                  
          this.client = client;
              }


              
          public void run() {
                  
          try {
                      
          // 顯示連接信息
                      describeConnectionInfo(client);
                      
          // 獲取流向到客戶端的輸出流
                      BufferedOutputStream outStream = new BufferedOutputStream(client
                              .getOutputStream());
                      
          // 獲取來自客戶端的輸入流 
                      HTTPInputStream inStream = new HTTPInputStream(client
                              .getInputStream());
                      
          // 得到客戶端的請求頭(自定義類) 
                      HTTPRequest request = inStream.getRequest();
                      
          // 顯示頭信息 
                      request.log();
                      
          // 目前只處理GET請求 
                      if (request.isGetRequest()){
                          processGetRequest(request, outStream);
                      }

                      System.out.println(
          "Request completed. Closing connection.");
                      
          //關閉socket 
                      client.close();
                  }
           catch (IOException e) {
                      System.out.println(
          "IOException occurred .");
                      e.printStackTrace();
                  }

              }


              
          // 顯示socket連接信息
              void describeConnectionInfo(Socket client) {
                  
          //客戶端的主機名 
                  String destName = client.getInetAddress().getHostName();
                  
          //客戶端的IP地址 
                  String destAddr = client.getInetAddress().getHostAddress();
                  
          //客戶端的端口 
                  int destPort = client.getPort();
                  
          //打印信息,表示客戶端已經連接到本服務器上 
                  System.out.println("Accepted connection to " + destName + " ("
                          
          + destAddr + ")" + " on port " + destPort + ".");
              }


              
          // 處理GET請求 
              void processGetRequest(HTTPRequest request, BufferedOutputStream outStream)
                      
          throws IOException {
                  
          // 獲得客戶端要get的文件名
                  String fileName = request.getFileName();
                  File file 
          = new File(fileName);
                  
          // 如果文件存在,則將文件內容發送到socket的輸出流,即客戶端。 
                  if (file.exists()){
                      sendFile(outStream, file);
                  }
           else {
                      System.out.println(
          "File " + file.getCanonicalPath()
                              
          + " does not exist.");
                  }

              }


              
          //  發送文件內容到客戶端,這里以HTTP 1.1的協議實現的
              void sendFile(BufferedOutputStream out, File file) {
                  
          try {
                      
          // 將文件內容全部讀入到一個字節數組中
                      DataInputStream in = new DataInputStream(new FileInputStream(file));
                      
          int len = (int) file.length();
                      
          byte buffer[] = new byte[len];
                      
          // 完全讀取,然后關閉文件流
                      in.readFully(buffer);
                      in.close();
                      
                      
          // 寫到socket的輸出流中
                      out.write("HTTP/1.1 200 OK\r\n".getBytes());
                      out.write((
          "Content-Length: " + buffer.length + "\r\n").getBytes());
                      out.write(
          "Content-Type: text/HTML\r\n\r\n".getBytes());
                      out.write(buffer);
                      out.flush();
                      out.close();
                      
          // 寫文件內容結束,log信息
                      System.out.println("File sent: " + file.getCanonicalPath());
                      System.out.println(
          "Number of bytes: " + len);
                  }
           catch (Exception e) {
                      
          try {
                          
          // 發送失敗
                          out.write(("HTTP/1.1 400 " + "No can do" + "\r\n").getBytes());
                          out.write(
          "Content-Type: text/HTML\r\n\r\n".getBytes());
                      }
           catch (IOException ioe) {
                      }

                      System.out.println(
          "Error retrieving " + file);
                  }

              }

          }


          /**
           * 實現讀客戶端請求的幫助類
           
          */

          class HTTPInputStream extends FilterInputStream {
              
          public HTTPInputStream(InputStream in) {
                  
          super(in);
              }


              
          // 讀一行,當輸入流中沒有數據,或者讀到"\r\n"時,一行結束。 
              public String readLine() throws IOException {
                  StringBuffer result 
          = new StringBuffer();
                  
          boolean finished = false;
                  
          //'\r'為回車符,值為13,'\n'為換行符,值為10
                  
          // cr變量表示是否已經讀到換行符
                  boolean cr = false;
                  
          do {
                      
          int ch = -1;
                      
          // 讀一個字節
                      ch = read();
                      
          if (ch == -1){
                          
          return result.toString();
                      }

                      result.append((
          char) ch);
                      
          //去掉最后的'\r\n' 
                      if (cr && (ch == 10)) {
                          result.setLength(result.length() 
          - 2);
                          
          return result.toString();
                      }

                      
          //讀到回車符,設置標識 
                      if (ch == 13){
                          cr 
          = true;
                      }
           else {
                          cr 
          = false;
                      }

                  }
           while (!finished);
                  
          return result.toString();
              }


              
          // 得到所有的請求 
              public HTTPRequest getRequest() throws IOException {
                  HTTPRequest request 
          = new HTTPRequest();
                  String line;
                  
          do {
                      
          // 依次讀取
                      line = readLine();
                      
          //將請求填入容器 
                      if (line.length() > 0){
                          request.addLine(line);
                      }
           else {
                          
          break;
                      }

                  }
           while (true);
                  
          // 返回
                  return request;
              }

          }


          // 客戶端請求的封裝類 
          class HTTPRequest {
              
          // 請求的數據,按行存儲
              Vector lines = new Vector();
              
          public HTTPRequest() {
              }


              
          public void addLine(String line) {
                  lines.addElement(line);
              }


              
          // 判斷是否是Get請求 
              boolean isGetRequest() {
                  
          if (lines.size() > 0{
                      
          // 獲取請求內容的第一行,如果頭三個字符是"GET",則為Get請求
                      String firstLine = (String) lines.elementAt(0);
                      
          if (firstLine.length() > 0){
                          
          if (firstLine.substring(03).equalsIgnoreCase("GET")){
                              
          return true;
                          }

                      }

                  }

                  
          return false;
              }


              
          // 從請求中解析到文件名 
              
          // 一般第一行的消息如此類格式:"GET /hehe.htm HTTP/1.1"
              /**
               * 從請求中解析到文件名,只需要處理第一行即可。
               * 第一行的格式有如下幾種:
               * (1)如果請求的URL為"
          http://localhost:80/test/hehe.htm",
               * 則第一行的內容為"GET /test/hehe.htm HTTP/1.1"。
               * (2)如果請求的URL為"
          http://localhost:80",
               * 則第一行的內容為"GET HTTP/1.1",此時應該找默認的html文件,如index.htm
               * (3)如果請求的URL為"
          http://localhost:80/test",
               * 則第一行的內容為"GET /test/ HTTP/1.1",此時應該找test目錄下默認的html文件
               
          */

              String getFileName() 
          {
                  
          if (lines.size() > 0{
                      
          //得到vector中第一個元素 
                      String firstLine = (String) lines.elementAt(0);

                      System.out.println(
          "firstLine:  " + firstLine);
                      
          //根據http消息格式得到文件名
                      String fileName = firstLine.substring(firstLine.indexOf(" "+ 1);
                      
          int n = fileName.indexOf(" ");
                      
          //URL在兩個空格之間 
                      if (n != -1){
                          fileName 
          = fileName.substring(0, n);
                      }


                      
          //去掉第一個'/' 
                      try {
                          
          if (fileName.charAt(0== '/'){
                              fileName 
          = fileName.substring(1);
                          }

                      }
           catch (StringIndexOutOfBoundsException ex) {
                      }


                      
          //默認首頁,這里認為index.htm為默認的首頁
                      
          //類似于'http://localhost:80'的情況 
                      if (fileName.equals("")){
                          fileName 
          = "index.htm";
                      }

                      
          //類似于'http://localhost:80/download/'的情況 
                      if (fileName.charAt(fileName.length() - 1== '/'){
                          fileName 
          += "index.htm";
                      }

                      System.out.println(
          "fileName:  " + fileName);
                      
          return fileName;
                  }
           else {
                      
          return "";
                  }

              }


              
          // 顯示請求信息 
              void log() {
                  System.out.println(
          "Received the following request:");
                  
          for (int i = 0; i < lines.size(); ++i){
                      System.out.println((String) lines.elementAt(i));
                  }

              }

          }


                                                                                                                 --    學海無涯
                  

          主站蜘蛛池模板: 股票| 连江县| 墨竹工卡县| 海晏县| 兰西县| 绥中县| 锦州市| 邹城市| 巴彦县| 吕梁市| 怀来县| 嘉祥县| 叙永县| 家居| 洪江市| 宁明县| 榕江县| 琼海市| 叙永县| 高州市| 赫章县| 腾冲县| 榕江县| 淮阳县| 宜兴市| 康平县| 桓仁| 海淀区| 博湖县| 靖边县| 平武县| 宁陵县| 沙雅县| 湄潭县| 三河市| 开平市| 淳化县| 长兴县| 五华县| 荔波县| 巴马|