4

Implementing server-sent events is on the face of it quite a simple task. Borrowing the examples in the Mozilla documentation the client side code would be along the lines of

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

What I have difficulty understanding is what happens server side. The things that puzzle me

  • So you want to keep sending out events from ssdemo.php means that you need to run it in a loop and let it sleep when it isn't sending
  • But by default Apache is setup to kill scripts that take "too long" to execute so this cannot be an infinite loop unless you setup that script run that way
  • If I have 10 users who come in requesting the same SSE service (ssdemo.php) would it then mean that I would have 10 instances of that looped script?

I suspect that my understanding of how the server side code works, should be coded is either flawed or naive or both. I would much appreciate any pointers to the right way to do this.

Charles
  • 50,943
  • 13
  • 104
  • 142
DroidOS
  • 8,530
  • 16
  • 99
  • 171

2 Answers2

2

Your understanding is correct. PHP needs to keep running, and in PHP you will need a loop, and you'll quickly run out of free Apache threads.

If you need to handle lots of connections you need to use event-based server like Node.js or Tornado that can handle lots of open connections.

If you'd rather use PHP, then a partial solution is to close connection after few seconds. The browser will reconnect, so you'll get a hybrid of polling and SSE.

In PHP you can check sys_getloadavg() to decide whether you can keep connection open or you're running short on free processes.

Kornel
  • 97,764
  • 37
  • 219
  • 309
0

I've been looking to answer the same kind of questions when it comes to SSE, here's my research:

I have a basic javax HttpServlet that will print data to a PrintWriter every rando seconds.

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");
}

and here is the script that fills a {textarea id="displayTextArea} element

<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>

-To answer your first question:
If you watch the console when you run the application you will notice that console doesn't print "You just entered the doGetMethod" until you send an HTTP GET request to the servlet path. This confirms the understanding that a Servlet instance and the req/resp objects are not created until someone calls the servlet. How do servlets work?
-Second and Third question:
Tomcat, by default, will assign one thread per connection (Source). On my current configuration, my program will max out at 6 connections. Each connection will create its own instance of the servlet, and while the connection is open, will stay in the while loop. This was proven when I ran server and opened separate connections, seeing different times and sequence of random intervals. My while loop is not infinite although_ It waits until a connection is closed and will then throw an exception and break the while loop. After the connection is closed the servlet will close.

The way I have done this is very much amateur way of doing SSE. If you want to study an advanced library for this I would check out jeaSSE

If anyone wants the complete code

Piyin
  • 1,823
  • 1
  • 16
  • 23
code_disciple
  • 182
  • 2
  • 17