服务器发送事件,服务器端代码。

4

实现服务器发送事件看起来是一项相当简单的任务。借鉴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个循环脚本的实例?
我怀疑我的理解和编码服务器端代码的方法可能存在缺陷或幼稚,如果您能指出正确的方法,我将不胜感激。
2个回答

2
您的理解是正确的。PHP需要持续运行,在PHP中您需要一个循环,否则很快就会耗尽Apache线程。
如果您需要处理大量连接,则需要使用基于事件的服务器,如Node.js或Tornado,可以处理大量打开的连接。
如果您更喜欢使用PHP,则部分解决方案是在几秒钟后关闭连接。浏览器将重新连接,因此您将获得轮询和SSE的混合体。
在PHP中,您可以检查sys_getloadavg()以决定是否可以保持连接打开或者您的空闲进程不足。

0

我一直在寻找关于SSE的类似问题的答案,以下是我的研究结果:

我有一个基本的javax HttpServlet,每隔几秒钟就会向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>

-回答你的第一个问题:
如果你在运行应用程序时观察控制台,你会注意到直到你发送HTTP GET请求到servlet路径时,控制台才不会打印“您刚刚输入了doGetMethod”。这证实了Servlet实例和req/resp对象在有人调用servlet之前是不会被创建的。Servlet如何工作?
-第二和第三个问题:
默认情况下,Tomcat将为每个连接分配一个线程(来源)。在我的当前配置中,我的程序将在6个连接处达到最大值。每个连接都将创建自己的servlet实例,并且在连接打开时,将保持在while循环中。当我运行服务器并打开单独的连接时,看到不同的时间和随机间隔序列,这一点得到了证明。我的while循环不是无限的,尽管它会等待直到连接关闭,然后抛出异常并退出while循环。连接关闭后,servlet将关闭。

我做这件事的方式非常业余,不是很专业的SSE方法。如果你想研究一个高级库来完成这个任务,我建议你查看一下jeaSSE

如果有人想要完整的代码,请联系我。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接