大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

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

Tomcat 高級 IO 機制

Tomcat高級 IO 機制簡介

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

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

Comet 支持

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

1. Comet 事件

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

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

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

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

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

2. Comet 過濾器

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

3. 范例代碼

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

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 連接設(shè)置單獨的超時。只需設(shè)置一個如下所示的請求屬性即可設(shè)置超時:

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

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

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

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

異步寫操作

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

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

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

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

注意,使用 sendfile 將禁止 Tomcat 可能在響應(yīng)中執(zhí)行的壓縮操作。

全部教程
主站蜘蛛池模板: 国产麻豆高清视频在线第一页 | 日本毛片在线观看 | 澳门一级特黄录像免费播黄 | 青青久久国产 | 日日摸夜夜爽日日放碰 | 亚洲第一区视频在线观看 | 国产成人香蕉在线视频网站 | 一级二级三级毛片 | 亚洲天堂久久 | 欧美在线精品一区二区三区 | 国产精品嫩草影院99av视频 | 日本四虎影视 | 一区二区三区亚洲视频 | 国产精品三区四区 | 日本成本人在线观看免费视频 | 奇米第四狠狠777高清秒播 | 亚洲精品不卡午夜精品 | 久久精选视频 | 亚洲综合爱爱久久网 | 国产高清在线a视频大全凹凸 | 综合中文字幕 | 精品国产一区二区三区久 | 久久久久久久久综合 | 亚洲国产精品一区二区不卡 | 青草草在线观看 | 欧美性猛交xxxx免费看久久久 | 伊人骚| 看免费的毛片 | 久久久高清日本道免费观看 | 四虎精品久久久久影院 | 国产精品九九视频 | 成人黄色一级毛片 | se成人国产精品 | 欧美成人午夜影院 | 一 级做人爱全视频在线看 一a级毛片 | 理论片毛片 | 欧美成人免费看片一区 | 精品久久久久久久久久中文字幕 | 九九热精品视频在线观看 | 亚洲一二区视频 | 五月花激情网 |