2013-07-25 163 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