• <menu id="eeoky"><tt id="eeoky"></tt></menu>
  • <nav id="eeoky"></nav>
  • Tomca教程
    Tomcat Manager
    Tomcat Realm 配置
    Tomcat 安全管理
    Tomcat JNDI 資源
    Tomcat JDBC 數據源
    Tomcat 類加載機制
    Tomcat JSPs
    Tomcat SSL/TLS配置
    Tomcat SSI
    Tomcat CGI
    Tomcat 代理支持
    Tomcat MBean 描述符
    Tomcat 默認 Servlet
    Tomcat 集群
    Tomcat 連接器
    Tomcat監控與管理
    Tomcat 日志機制
    Tomcat 基于 APR 的原生庫
    Tomcat 虛擬主機
    Tomcat 高級 IO 機制
    Tomcat 附加組件
    Tomcat 安全性注意事項
    Tomcat Windows 服務
    Tomcat Windows 認證
    Tomcat 的 JDBC 連接池
    Tomcat WebSocket 支持
    Tomcat 重寫機制

    Tomcat 高級 IO 機制

    Tomcat高級 IO 機制簡介

    由于基于 APR 或 NIO API 來構建連接器,Tomcat 能在通常的阻塞 IO 之上提供一些擴展,從而支持 Servlet API。

    重要說明:這些特性需要使用 APR 或 NIO HTTP 連接器。經典的 java.io HTTP 連接器 與 AJP 連接器并不支持它們。

    Comet 支持

    Comet 支持能讓 Servlet 實現:對 IO 的異步處理;當連接可以讀取數據時,接收事件(而不是總使用阻塞讀?。?;將數據異步地寫入連接(很可能是響應其他一些源所產生的事件)。

    1. Comet 事件

    根據發生的具體事件,實現 org.apache.catalina.comet.CometProcessor 接口的 Servlet 將調用自己的事件方法,而非通常的服務方法。事件對象允許訪問常見的請求與響應對象,使用方式與通常方式相同。主要的區別在于:在處理 BEGIN 事件到 END 或 ERROR 事件之間,這些事件對象能夠保持有效和完整的功能性。事件類型如下:

    • EventType.BEGIN 在連接處理開始時被調用,用來初始化使用了請求和響應對象的相關字段。從處理完該事件后直到 END 或 ERROR 事件開始處理時的這段時間內,有可能使用響應對象在開放連接中寫入數據。注意,響應對象以及所依賴的 OutputStream 和 Writer 仍不能同步,因此在通過多個線程訪問它們時,需要進行強制實現同步操作。處理完初始化事件后,就可以提交請求對象了。
    • EventType.READ 該事件表明可以使用輸入數據,讀取過程不會阻塞??梢允褂?InputStream 或 Reader 的 available 和 ready 方法來確定是否存在阻塞危險:當數據被報告可讀時,Servlet 應該進行讀取。當讀取遇到錯誤時,Servlet 可以通過正確傳播 Exception 屬性來報告這一情況。拋出異常會導致 ERROR 事件的調用,連接就會關閉。另外,也有可能捕獲一個異常,在 Servlet 可能使用的數據結構上進行清理,然后使用事件的 close 方法。不允許從 Servlet 對象執行方法外部去讀取數據。
    • 在一些平臺(比如 Windows)上,利用 READ 事件來表示客戶端斷開連接。從流中讀取的結果可能是 -1、IOException 異?;?EOFException 異常。一定要正確處理這些情況。如果你沒有捕捉到 IOException 異常,那么當 Tomcat 捕獲到異常時,它會立刻調用你的事件隊列生成一個 ERROR 事件來存儲這些錯誤,并且你會馬上收到這個消息。
    • EventType.END 請求處理完畢時,就會調用 END 方法。Begin 方法初始化的字段也將被重置。在處理完這一事件后,請求和響應對象,以及它們所依賴的對象,都將被回收,以便再去處理其他請求。當數據可讀取時,以及到達請求輸入的文件末尾時(這通常表明客戶端通過管線提交請求),也會調用 END。
    • EventType.ERROR:當連接上出現 IO 異?;蝾愃频牟豢苫厥盏腻e誤時,容器就會調用 ERROR。在開始時候被初始化的字段在這時候被重置。在處理完這一事件后,請求和響應對象,以及它們所依賴的對象,都將被回收,以便再去處理其他請求。

    下面是一些事件子類別,通過它們可以對事件處理過程進行微調(注意:其中有些事件可能需要使用 org.apache.catalina.valves.CometConnectionManagerValve 值):

    • EventSubType.TIMEOUT: 連接超時(ERROR 的子類別)。注意,這個 ERROR 子類型并不是必須的。除非 servlet 使用該事件的 close 方法,否則連接將不會關閉。
    • EventSubType.CLIENT_DISCONNECT:客戶端連接被關閉(ERROR 的子類別)。
    • EventSubType.IOEXCEPTION:表示發生了 IO 異常(比如無效內容),例如無效的塊阻塞(ERROR 的子類別)。
    • EventSubType.WEBAPP_RELOAD:重新加載 Web 應用(END 的子類別)。
    • EventSubType.SESSION_END:Servlet 終止了會話(END 的子類別)。

    如上所述,Comet 請求的典型生命周期會包含一系列的事件:BEGIN -> READ -> READ -> READ -> ERROR/TIMEOUT。任何時候,Servlet 都能用事件的 close 方法來終止對請求的處理。

    2. Comet 過濾器

    跟一般的過濾器一樣,當處理 Comet 事件時,就會調用一個過濾器隊列。這些過濾器應該實現 CometFilter 接口(和常用的過濾器接口一樣),在部署描述符文件中的聲明與映像也都和通常的過濾器一樣。當過濾器隊列在處理事件時,它將只含有那些跟所有通常映射規則相匹配的過濾器,并且這些過濾器要實現 CometFilter 接口。

    3. 范例代碼

    在下面的范例偽碼中,通過使用上文所述的 API,Servlet 實現了異步聊天功能。

    public class ChatServlet
        extends HttpServlet implements CometProcessor {
    
        protected ArrayList connections =
            new ArrayList();
        protected MessageSender messageSender = null;
    
        public void init() throws ServletException {
            messageSender = new MessageSender();
            Thread messageSenderThread =
                new Thread(messageSender, "MessageSender[" + getServletContext().getContextPath() + "]");
            messageSenderThread.setDaemon(true);
            messageSenderThread.start();
        }
    
        public void destroy() {
            connections.clear();
            messageSender.stop();
            messageSender = null;
        }
    
        /**
         * Process the given Comet event.
         *
         * @param event The Comet event that will be processed
         * @throws IOException
         * @throws ServletException
         */
        public void event(CometEvent event)
            throws IOException, ServletException {
            HttpServletRequest request = event.getHttpServletRequest();
            HttpServletResponse response = event.getHttpServletResponse();
            if (event.getEventType() == CometEvent.EventType.BEGIN) {
                log("Begin for session: " + request.getSession(true).getId());
                PrintWriter writer = response.getWriter();
                writer.println("");
                writer.println("JSP Chat
    ");
     writer.flush();
                synchronized(connections) {
                    connections.add(response);
                }
            } else if (event.getEventType() == CometEvent.EventType.ERROR) {
                log("Error for session: " + request.getSession(true).getId());
                synchronized(connections) {
                    connections.remove(response);
                }
                event.close();
            } else if (event.getEventType() == CometEvent.EventType.END) {
                log("End for session: " + request.getSession(true).getId());
                synchronized(connections) {
                    connections.remove(response);
                }
                PrintWriter writer = response.getWriter();
                writer.println("
    
    ");
                event.close();
            } else if (event.getEventType() == CometEvent.EventType.READ) {
                InputStream is = request.getInputStream();
                byte[] buf = new byte[512];
                do {
                    int n = is.read(buf); //can throw an IOException
                    if (n > 0) {
                        log("Read " + n + " bytes: " + new String(buf, 0, n)
                                + " for session: " + request.getSession(true).getId());
                    } else if (n < 0) {
                        error(event, request, response);
                        return;
                    }
                } while (is.available() > 0);
            }
        }
    
        public class MessageSender implements Runnable {
    
            protected boolean running = true;
            protected ArrayList messages = new ArrayList();
    
            public MessageSender() {
            }
    
            public void stop() {
                running = false;
            }
    
            /**
             * Add message for sending.
             */
            public void send(String user, String message) {
                synchronized (messages) {
                    messages.add("[" + user + "]: " + message);
                    messages.notify();
                }
            }
    
            public void run() {
    
                while (running) {
    
                    if (messages.size() == 0) {
                        try {
                            synchronized (messages) {
                                messages.wait();
                            }
                        } catch (InterruptedException e) {
                            // Ignore
                        }
                    }
    
                    synchronized (connections) {
                        String[] pendingMessages = null;
                        synchronized (messages) {
                            pendingMessages = messages.toArray(new String[0]);
                            messages.clear();
                        }
                        // Send any pending message on all the open connections
                        for (int i = 0; i < connections.size(); i++) {
                            try {
                                PrintWriter writer = connections.get(i).getWriter();
                                for (int j = 0; j < pendingMessages.length; j++) {
                                    writer.println(pendingMessages[j] + "
    ");
                                }
                                writer.flush();
                            } catch (IOException e) {
                                log("IOExeption sending message", e);
                            }
                        }
                    }
    
                }
    
            }
    
        }
    
    }

    4. Comet 超時

    如果使用 NIO 連接器,你可以為不同的 comet 連接設置單獨的超時。只需設置一個如下所示的請求屬性即可設置超時:

    CometEvent event.... event.setTimeout(30*1000);

    event.getHttpServletRequest().setAttribute("org.apache.tomcat.comet.timeout", new Integer(30 * 1000));

    超時被設置為 30 秒。重要說明:為了設置超時,必須完成 BEGIN 事件。默認值為 soTimeout。

    如果使用 APR 連接器,所有的 Comet 連接將擁有統一的超時值:soTimeout*50。

    異步寫操作

    當 APR 或 NIO 可用時,Tomcat 支持使用 sendfile 方式去發送大型靜態文件。只要系統負載一增加,就會異步地高效執行寫操作。作為一種使用阻塞寫操作發送大型響應的替代方式,有可能使用 sendfile 代碼來將內容寫入靜態文件。緩存值將利用這一點將響應數據緩存至文件而非存儲在內存中。如果請求屬性 org.apache.tomcat.sendfile.support 設為 Boolean.TRUE,則表示支持 sendfile。

    通過合適的請求屬性,任何 Servlet 都可以指示 Tomcat 執行 sendfile 調用。正確地設置響應長度也是很有必要的。在使用 sendfile 時,最好確定請求與響應都沒有被包裝起來。因為稍后連接器本身將發送響應主體,所以不能夠過濾響應主體。除了設置 3 個所需的請求屬性之外,Servlet 不應該發送任何響應數據,但能使用一些能夠修改響應報頭的方法(比如設定 cookie)。

    • org.apache.tomcat.sendfile.filename 作為字符串發送的標準文件名。
    • org.apache.tomcat.sendfile.start開始位置偏移值,長整型值。
    • org.apache.tomcat.sendfile.end 結束位置偏移值,長整型值。

    除了設置這些屬性,還有必要設置內容長度報頭。不要指望 Tomcat 來處理,因為你可能已經將數據寫入輸出流了。

    注意,使用 sendfile 將禁止 Tomcat 可能在響應中執行的壓縮操作。

    全部教程
    疯狂婬荡乱婬A片中文,特级西西人体444WWw高清大胆,国产性XXXX18免费观看视频,中文字幕乱伦,free性满足HD国产精品,牛人女厕偷拍1区2区