<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    paulwong

    簡單的用 Java Socket 編寫的 HTTP 服務(wù)器應(yīng)用,幫助學(xué)習(xí)HTTP協(xié)議

    所謂HTTP協(xié)議,就是TCP協(xié)議+狀態(tài)信息之類的字符。

    資源:http://www.tkk7.com/nokiaguy/category/38517.html

    /**
     * SimpleHttpServer.java
     
    */

    import java.io.*;
    import java.net.*;
    import java.util.StringTokenizer;

    /**
     * 一個簡單的用 Java Socket 編寫的 HTTP 服務(wù)器應(yīng)用, 演示了請求和應(yīng)答的協(xié)議通信內(nèi)容以及
     * 給客戶端返回 HTML 文本和二進(jìn)制數(shù)據(jù)文件(一個圖片), 同時展示了 404, 200 等狀態(tài)碼.
     * 首先運(yùn)行這個程序,然后打開Web瀏覽器,鍵入http://localhost,則這個程序能夠顯示出瀏覽器發(fā)送了那些信息
     * 并且向?yàn)g覽器返回一個網(wǎng)頁和一副圖片, 并測試同瀏覽器對話.
     * 當(dāng)瀏覽器看到 HTML 中帶有圖片地址時, 則會發(fā)出第二次連接來請求圖片等資源.
     * 這個例子可以幫您理解 Java 的 HTTP 服務(wù)器軟件是基于 J2SE 的 Socket 等軟件編寫的概念, 并熟悉
     * HTTP 協(xié)議.
     * 相反的用 Telnet 連接到已有的服務(wù)器則可以幫忙理解瀏覽器的運(yùn)行過程和服務(wù)器端的返回內(nèi)容.
     *
     * <pre>
     *       當(dāng)用戶在Web瀏覽器地址欄中輸入一個帶有http://前綴的URL并按下Enter后,或者在Web頁面中某個以http://開頭的超鏈接上單擊鼠標(biāo),HTTP事務(wù)處理的第一個階段--建立連接階段就開始了.HTTP的默認(rèn)端口是80.
     *    隨著連接的建立,HTTP就進(jìn)入了客戶向服務(wù)器發(fā)送請求的階段.客戶向服務(wù)器發(fā)送的請求是一個有特定格式的ASCII消息,其語法規(guī)則為:
     * < Method > < URL > < HTTP Version > <\n>
     * { <Header>:<Value> <\n>}*
     * <\n>
     * { Entity Body }
     *    請求消息的頂端是請求行,用于指定方法,URL和HTTP協(xié)議的版本,請求行的最后是回車換行.方法有GET,POST,HEAD,PUT,DELETE等.
     * 在請求行之后是若干個報(bào)頭(Header)行.每個報(bào)頭行都是由一個報(bào)頭和一個取值構(gòu)成的二元對,報(bào)頭和取值之間以":"分隔;報(bào)頭行的最后是回車換行.常見的報(bào)頭有Accept(指定MIME媒體類型),Accept_Charset(響應(yīng)消息的編碼方式),Accept_Encoding(響應(yīng)消息的字符集),User_Agent(用戶的瀏覽器信息)等.
     *    在請求消息的報(bào)頭行之后是一個回車換行,表明請求消息的報(bào)頭部分結(jié)束.在這個\n之后是請求消息的消息實(shí)體(Entity Body).具體的例子參看httpRequest.txt.
     *     Web服務(wù)器在收到客戶請求并作出處理之后,要向客戶發(fā)送應(yīng)答消息.與請求消息一樣,應(yīng)答消息的語法規(guī)則為:
     * < HTTP Version> <Status Code> [<Message>]<\n>
     * { <Header>:<Value> <\n> } *
     * <\n>
     * { Entity Body }
     *    應(yīng)答消息的第一行為狀態(tài)行,其中包括了HTTP版本號,狀態(tài)碼和對狀態(tài)碼進(jìn)行簡短解釋的消息;狀態(tài)行的最后是回車換行.狀態(tài)碼由3位數(shù)字組成,有5類: 
     * 參看:HTTP應(yīng)答碼及其意義 
     * 
     * 1XX 保留 
     * 2XX 表示成功 
     * 3XX 表示URL已經(jīng)被移走 
     * 4XX 表示客戶錯誤 
     * 5XX 表示服務(wù)器錯誤 
     * 例如:415,表示不支持改媒體類型;503,表示服務(wù)器不能訪問.最常見的是200,表示成功.常見的報(bào)頭有:Last_Modified(最后修改時間),Content_Type(消息內(nèi)容的MIME類型),Content_Length(內(nèi)容長度)等.
     *    在報(bào)頭行之后也是一個回車換行,用以表示應(yīng)答消息的報(bào)頭部分的結(jié)束,以及應(yīng)答消息實(shí)體的開始.
     *    下面是一個應(yīng)答消息的例子:
     * HTTP/1.0 200 OK
     * Date: Moday,07-Apr-97 21:13:02 GMT
     * Server:NCSA/1.1
     * MIME_Version:1.0
     * Content_Type:text/html
     * Last_Modified:Thu Dec 5 09:28:01 1996
     * Coentent_Length:3107
     * 
     * <HTML><HEAD><TITLE></HTML>
     * 
     * 在用Java語言實(shí)現(xiàn)HTTP服務(wù)器時,首先啟動一個java.net.ServerSocket在提供服務(wù)的端口上監(jiān)聽連接.向客戶返回文本時,可以用PrintWriter,但是如果返回二進(jìn)制數(shù)據(jù),則必須使用OutputStream.write(byte[])方法,返回的應(yīng)答消息字符串可以使用String.getBytes()方法轉(zhuǎn)換為字節(jié)數(shù)組返回,或者使用PrintStream的print()方法寫入文本,用write(byte[])方法寫入二進(jìn)制數(shù)據(jù).
     * 
     * </pre>
     * 
    @author 劉長炯
     * 
    @version 1.0 2007-07-24 Sunday
     
    */
    public class SimpleHttpServer implements Runnable {
        /**
         * 
         
    */
        ServerSocket serverSocket;//服務(wù)器Socket
        
        /**
         * 服務(wù)器監(jiān)聽端口, 默認(rèn)為 80.
         
    */
        public static int PORT=80;//標(biāo)準(zhǔn)HTTP端口
        
        /**
         * 開始服務(wù)器 Socket 線程.
         
    */
        public SimpleHttpServer() {
            try {
                serverSocket=new ServerSocket(PORT);
            } catch(Exception e) {
                System.out.println("無法啟動HTTP服務(wù)器:"+e.getLocalizedMessage());
            }
            if(serverSocket==null)  System.exit(1);//無法開始服務(wù)器
            new Thread(this).start();
            System.out.println("HTTP服務(wù)器正在運(yùn)行,端口:"+PORT);
        }
        
        /**
         * 運(yùn)行服務(wù)器主線程, 監(jiān)聽客戶端請求并返回響應(yīng).
         
    */
        public void run() {
            while(true) {
                try {
                    Socket client=null;//客戶Socket
                    client=serverSocket.accept();//客戶機(jī)(這里是 IE 等瀏覽器)已經(jīng)連接到當(dāng)前服務(wù)器
                    if(client!=null) {
                        System.out.println("連接到服務(wù)器的用戶:"+client);
                        try {
                            // 第一階段: 打開輸入流
                            BufferedReader in=new BufferedReader(new InputStreamReader(
                                    client.getInputStream()));
                            
                            System.out.println("客戶端發(fā)送的請求信息:\n***************");
                            // 讀取第一行, 請求地址
                            String line=in.readLine();
                            System.out.println(line);
                            String resource=line.substring(line.indexOf('/'),line.lastIndexOf('/')-5);
                            //獲得請求的資源的地址
                            resource=URLDecoder.decode(resource, "UTF-8");//反編碼 URL 地址
                            String method = new StringTokenizer(line).nextElement().toString();// 獲取請求方法, GET 或者 POST

                            
    // 讀取所有瀏覽器發(fā)送過來的請求參數(shù)頭部信息
                            while( (line = in.readLine()) != null) {
                                System.out.println(line);
                                
                                if(line.equals("")) break;
                            }
                            
                            // 顯示 POST 表單提交的內(nèi)容, 這個內(nèi)容位于請求的主體部分
                            if("POST".equalsIgnoreCase(method)) {
                                System.out.println(in.readLine());
                            }
                            
                            System.out.println("請求信息結(jié)束\n***************");
                            System.out.println("用戶請求的資源是:"+resource);
                            System.out.println("請求的類型是: " + method);

                            // GIF 圖片就讀取一個真實(shí)的圖片數(shù)據(jù)并返回給客戶端
                            if(resource.endsWith(".gif")) {
                                fileService("images/test.gif", client);
                                closeSocket(client);
                                continue;
                            }
                            
                            // 請求 JPG 格式就報(bào)錯 404
                            if(resource.endsWith(".jpg")) {
                                                        PrintWriter out=new PrintWriter(client.getOutputStream(),true);
                            out.println("HTTP/1.0 404 Not found");//返回應(yīng)答消息,并結(jié)束應(yīng)答
                            out.println();// 根據(jù) HTTP 協(xié)議, 空行將結(jié)束頭信息
                            out.close();
                            closeSocket(client);
                            continue;
                            } else {
                                // 用 writer 對客戶端 socket 輸出一段 HTML 代碼
                                PrintWriter out=new PrintWriter(client.getOutputStream(),true);
                                out.println("HTTP/1.0 200 OK");//返回應(yīng)答消息,并結(jié)束應(yīng)答
                                out.println("Content-Type:text/html;charset=GBK");
                                out.println();// 根據(jù) HTTP 協(xié)議, 空行將結(jié)束頭信息

                                out.println("<h1> Hello Http Server</h1>");
                                out.println("你好, 這是一個 Java HTTP 服務(wù)器 demo 應(yīng)用.<br>");
                                out.println("您請求的路徑是: " + resource + "<br>");
                                out.println("這是一個支持虛擬路徑的圖片:<img src='abc.gif'><br>" +
                                        "<a href='abc.gif'>點(diǎn)擊打開abc.gif, 是個服務(wù)器虛擬路徑的圖片文件.</a>");
                                out.println("<br>這是個會反饋 404 錯誤的的圖片:<img src='test.jpg'><br><a href='test.jpg'>點(diǎn)擊打開test.jpg</a><br>");
                                out.println("<form method=post action='/'>POST 表單 <input name=username value='用戶'> <input name=submit type=submit value=submit></form>");
                                out.close();

                                closeSocket(client);
                            }
                        } catch(Exception e) {
                            System.out.println("HTTP服務(wù)器錯誤:"+e.getLocalizedMessage());
                        }
                    }
                    //System.out.println(client+"連接到HTTP服務(wù)器");//如果加入這一句,服務(wù)器響應(yīng)速度會很慢
                } catch(Exception e) {
                    System.out.println("HTTP服務(wù)器錯誤:"+e.getLocalizedMessage());
                }
            }
        }
        
        /**
         * 關(guān)閉客戶端 socket 并打印一條調(diào)試信息.
         * 
    @param socket 客戶端 socket.
         
    */
        void closeSocket(Socket socket) {
            try {
                socket.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
                                System.out.println(socket + "離開了HTTP服務(wù)器");        
        }
        
        /**
         * 讀取一個文件的內(nèi)容并返回給瀏覽器端.
         * 
    @param fileName 文件名
         * 
    @param socket 客戶端 socket.
         
    */
            void fileService(String fileName, Socket socket)
        {
                
            try
            {
                PrintStream out = new PrintStream(socket.getOutputStream(), true);
                File fileToSend = new File(fileName);
                if(fileToSend.exists() && !fileToSend.isDirectory())
                {
                    out.println("HTTP/1.0 200 OK");//返回應(yīng)答消息,并結(jié)束應(yīng)答
                    out.println("Content-Type:application/binary");
                    out.println("Content-Length:" + fileToSend.length());// 返回內(nèi)容字節(jié)數(shù)
                    out.println();// 根據(jù) HTTP 協(xié)議, 空行將結(jié)束頭信息
                    
                    FileInputStream fis = new FileInputStream(fileToSend);
                    byte data[] = new byte[fis.available()];
                    fis.read(data);
                    out.write(data);
                    out.close();
                    fis.close();
                }
            }
            catch(Exception e)
            {
                System.out.println("傳送文件時出錯:" + e.getLocalizedMessage());
            }
        }
        
        /**
         * 打印用途說明.
         
    */
        private static void usage() {
            System.out.println("Usage: java HTTPServer <port>\nDefault port is 80.");
        }
        
        
        /**
         * 啟動簡易 HTTP 服務(wù)器
         * 
    @param args 
         
    */
        public static void main(String[] args) {
            try {
                if(args.length != 1) {
                    usage();
                } else if(args.length == 1) {
                    PORT = Integer.parseInt(args[0]);
                }
            } catch (Exception ex) {
                System.err.println("Invalid port arguments. It must be a integer that greater than 0");
            }
            
            new SimpleHttpServer();
        }
        

    posted on 2013-02-25 22:29 paulwong 閱讀(329) 評論(0)  編輯  收藏 所屬分類: J2SE

    主站蜘蛛池模板: 成人黄页网站免费观看大全| 国产伦一区二区三区免费 | 两性色午夜免费视频| 222www免费视频| 免费大黄网站在线观看| 亚洲好看的理论片电影| 久久亚洲欧美国产精品| 日本免费污片中国特一级| 免费高清在线影片一区| 久久精品国产亚洲av成人| 噜噜综合亚洲AV中文无码| 国产麻豆一精品一AV一免费| 国产三级免费电影| 亚洲国产精品成人精品软件 | 亚洲精品~无码抽插| 亚洲日韩中文字幕无码一区| 大地影院MV在线观看视频免费| 日本免费v片一二三区| 久久久久亚洲AV片无码下载蜜桃| 免费人成大片在线观看播放电影| 久久久久久久免费视频| 亚洲AV无码成人精品区在线观看| 欧洲亚洲综合一区二区三区| 精品福利一区二区三区免费视频 | 青娱乐在线视频免费观看| 麻豆国产精品免费视频| 亚洲精品无码鲁网中文电影| 狠狠入ady亚洲精品| 2021免费日韩视频网| 亚洲av永久无码精品漫画 | 亚洲一卡二卡三卡四卡无卡麻豆| 9久久免费国产精品特黄| 在线观看永久免费视频网站| 亚洲人成网站在线观看播放动漫 | 国产一卡二卡四卡免费| 久久亚洲精品视频| 免费无码午夜福利片 | 亚洲综合亚洲国产尤物| 久久久久国色AV免费观看| 免费在线观看黄网| 亚洲hairy多毛pics大全|