2013-07-25 160 views
3

實現服務器發送的事件是一個非常簡單的任務。借用的例子Mozilla的文檔中的客戶端代碼將沿服務器發送的事件,服務器端代碼

var evtSource = new EventSource("ssedemo.php"); 
evtSource.onmessage = function(e){//do stuff with e.data here} 

行我很難理解發生了什麼服務器端。讓我困惑

  • 的事情,所以你要不停地發送了事件從ssdemo.php意味着你需要在一個循環中運行它,讓它睡覺的時候它不發送
  • 但是通過默認的Apache被設置爲終止執行「太長」的腳本,因此這不能是無限循環,除非您設置該腳本以這種方式運行
  • 如果我有10個用戶請求相同的SSE服務(ssdemo.php)那麼它意味着我將有10個環形腳本的實例?

我懷疑我對服務器端代碼工作原理的理解應該是有缺陷的或者天真的或者兩者兼而有之。我非常感謝任何指向正確的方式來做到這一點。

回答

1

你的理解是正確的。 PHP需要繼續運行,並且在PHP中您將需要一個循環,並且您將很快耗盡免費的Apache線程。

如果您需要處理大量連接,您需要使用基於事件的服務器,如Node.js或Tornado,它可以處理大量打開的連接。

如果您想使用PHP,那麼部分解決方案是在幾秒鐘後關閉連接。瀏覽器將重新連接,所以你會得到輪詢和SSE的混合。

在PHP中,您可以檢查sys_getloadavg()以確定您是否可以保持連接處於打開狀態,或者您在空閒進程中運行不足。

0

我一直期待着回答同一個樣的問題,當涉及到SSE,這裏是我的研究:

我有一個基本的javax的HttpServlet,將打印數據每RANDO秒一個PrintWriter。

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { 
    System.out.println("You just entered the doGetMethod"); 
    response.setContentType("text/event-stream"); 
    response.setCharacterEncoding("UTF-8"); 
    PrintWriter printWriter = null; 
    while(true){ 
    try{ 
     System.out.println("You just entered the while loop"); 
     double randomNumber = Math.random()*10000; 
     printWriter = response.getWriter(); 
     printWriter.print("data: " + "[next server time check event in " + 
     Math.round(randomNumber/1000) + " seconds]\n"); 
     printWriter.print("data: " + "Time: " + Calendar.getInstance().getTime() + "\n\n"); 
     response.flushBuffer(); 
     Thread.sleep((long)randomNumber); 

    } catch (IOException | InterruptedException e){ 
     e.printStackTrace(); 
     break; 
    } 
    } 
    System.out.println("Connection was aborted"); 
} 

這裏是填補了{textarea的ID =「displayTextArea}元素

<script> 
    var eventSource = null; 
    function start(){ 
    eventSource = new EventSource('http://localhost:8080/SSEServlet'); 
    eventSource.onopen = function(){displayTextArea.value+='Connected ..' + '\n';}; 
    eventSource.onmessage = function(message){displayTextArea.value+=message.data + '\n\n';}; 
    eventSource.onerror = function(){displayTextArea.value+='Error Occurred...' + '\n';}; 
    } 
    function stop(){ 
    eventSource.close(); 
    } 
    function clearText(){ 
    displayTextArea.value = ''; 
    } 
</script> 

腳本 - 要回答你的第一個問題
如果你看控制檯當您運行應用程序中,您將注意到控制檯不會打印「您剛剛輸入了doGetMethod」,直到您向Servlet路徑發送HTTP GET請求爲止,這確認了Servlet實例和req/resp對象不會在有人呼叫servlet。How do servlets work?
- 第二和第三個問題:
默認情況下,Tomcat將爲每個連接分配一個線程(Source)。在我目前的配置下,我的程序最多可以連接6個連接。每個連接都將創建它自己的servlet實例,並且在連接打開時,將保留在while循環中。當我運行服務器並打開單獨的連接,看到不同的時間和隨機間隔的順序時,這已被證明。我的while循環不是無限的,雖然它一直等到連接關閉,然後會拋出異常並中斷while循環。連接關閉後,servlet將關閉。

我這樣做的方式非常非常做業餘SSE的方式。如果你想爲此學習高級圖書館,我會退房jeaSSE

如果有人想要完整code