Post Reply 
 
Thread Rating:
  • 0 Votes - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
HTTP Streaming testing results
08-12-2009, 03:49 AM
Post: #1
HTTP Streaming testing results
In a few of my tests, I found that:
  • The HTTP Response should include the HTTP header Transfer-Encoding: chunked
    When the HTTP 1.1 standard was released, Transfer-Encoding was expanded to allow for 'chunked' responses. Normally, when a client (i.e. your browser) requests a resource (such as an HTML page or an image), the server sends the complete content back to the client. The size of this resource (which is defined through the HTTP header Content-Length) is already known to the server. However, it became apparent during the first few years of HTTP 1.0 that the size of a resource may not always be known and the server needs a way of sending blocks of data to the client as they are received. This is where Transfer-Encoding: chunked comes into play. The way I do HTTP Streaming is by sending all my HTTP Headers first and then sending the Transfer-Encoding: chunked header next. At this point, I store the client connection object somewhere and exit out of my response method.

    As data comes in that needs to be sent to the client, I grab the connection that I stored and send a string in the following format:
    ----------

    <content size in hex format>
    <content>
    ----------

    Please note that the first line is an empty line on purpose and that every line must end with a CRLF combination.

    When the server wants to let the client know there is no data left to send, it simply sends the following string:
    ----------

    0

    ----------
    Again, the lines are left blank on purpose and must end with CRLF.
  • XMLHTTPRequest works with streaming, sometimes...
    In Firefox, XMLHTTPRequest works perfectly fine because whenever new data is sent, the onreadystatechange event is always fired. However, in IE7, this is not the case. Also, certain versions of IE have ActiveX versions instead of native browser versions so if the browser has disabled ActiveX, then XMLHTTPRequest won't work in this case either. But fear not, there is another solution that I actually find works better than XMLHTTPRequest for most of my Streaming tests

    Let's just say, though, that XMLHTTPRequest did work consistently among the main browsers. There is another annoyances to using XMLHTTPRequest: You have to poll/parse the data every time new data is sent down. Unlike the hidden IFRAME method (which will be described below), when new data is received, you'll have to find it yourself as there is no built-in mechanism to do it for already. While it's a fairly simple chunk of code to do this, it's just something else you'll need to implement.

    However, XMLHTTPRequest isn't without it's merits. Native support for being able to set HTTP headers and to get the HTTP headers for the response as well as the status code of a request is a big plus. While there are work-arounds in the hidden IFRAME method, it's something you'll need to implement yourself.
  • The hidden IFRAME works all the time
    Funny, but probably the oldest way of streaming HTTP also works the best. It is supported in all browsers with fairly consistent behaviors. Don't needs to poll the data as it comes in if you use <SCRIPT> tags around your messages.

    There is this interesting behavior with browsers. As they get completed SCRIPT tags (tags that are open and closed properly), they try to process them immediately. So HTTP streaming can be implemented as a series of <SCRIPT>---JavaScript code---</SCRIPT> messages sent to the client in a chunked transfer-encoding stream.

    Ok, so we are getting these JS snippets executed. How exactly do we incorporate that into our page? What is generally done is that the JS code that is sent is actually a method call to a function defined at either the Window level or the parent document level. It would normally be structured like this:
    Code:
    <script type='text/javascript'>window.parent.onServerMessage('some message');</script>
    This is the most common approach, but there are other ways of doing the same thing. Feel free to test them out.

So after doing a few different tests, I came to the conclusion that my HTTP Streaming should be implemented as such:
1) A hidden IFRAME is added dynamically to the page with an event handler on the OnLoad event to signal when the server closed the connection so that we can start it back up again.
2) The HTTP request that is sent via the IFRAME is a GET method with query string that lets the server know what the method is in the parent document that we will be calling.
3) Whenever data is to be sent to the server (as a POST) we will use XMLHTTPRequest to post the data and since we don't care what the response is (other than a non 200 HTTP response code), there isn't anything else we'll need to do.



There are a few things that needs to be reviewed further:
1) How long can the hidden IFRAME remain open for streaming before we start hitting performance and memory issues? 1 minute? 10MBs? These are all settings that can be modified at the server level or possibly be sent by the client in the request from the IFRAME.

2) Since there can be a delay in when data gets to the client from the server and anything can happen between the time the server sent the data versus when the client received and processed it (i.e. the user clicked a button that aborted the stream unexpectedly), the server should maintain a rolling history of past messages. Each message would be index and as they are sent to the client, those indexes are included. This way, a client can request a stream to start at a message by index to avoid losing any messages along the way when it restarts a stream.


Feel free to comment and/or add your thoughts to this.
Find all posts by this user
Quote this message in a reply
08-27-2009, 02:29 AM
Post: #2
RE: HTTP Streaming testing results
I have started to develop the JavaScript framework that I am going to use for my web client. However, during the development and trying to implement some real-world situations for this framework, I have come to realize that the hidden IFRAME implementation is annoying to work with when you are trying to abstract HTTP Streaming and deal with some of the annoying side-issues that come up with IFRAMEs such as the user stopping the download by hitting the Stop button or ESC and the forever running Throbber (that nice graphic that shows the page is loading).

So I decided to first implement HTTP Streaming using XMLHTTPRequest and long-polling for FireFox. If I architect the framework properly, I should be able to code a different implementation for IE.

This is how I'm implementing my HTTP Streaming:
From many of the posts I've ready regarding XHR and Long-polling, they usually have the XHR open the connection and wait for a response from the server. When that response comes (or a timeout/UI event occurs), then they close the connection and make a new request for new data.

I find this odd for HTTP Streaming because you are not optimizing the open connection that you have. The way I'm currently implementing my HTTP Streaming doesn't close right after a response is received. It only closes and reconnects after the timeout event occurs or data is to be sent to the server. This method, in my opinion, really cuts down the latency issues, especially for systems with a higher server message to client message ratio like a MUD. You are only wasting time reconnecting when needed, and not during some arbitrary event like a chat message over a Channel or an NPC walking in/out of a room.

It just makes sense to me to go that way.
Find all posts by this user
Quote this message in a reply
09-25-2009, 01:45 AM
Post: #3
RE: HTTP Streaming testing results
Hi there,

I chanced upon your forum post. in my search regarding an ajax mud..
so I was wondering... most of the old muds I've seen are diku etc.. mostly c, c++ or java mostly..

I'm relatively new to ajax and was wondering if ajax might work well with php, to make an ajax-mud.. with maybe a database like mysql?

I started thinking along the lines of like...
a user logs into the php mud game, makes a request.. which ajax sends to the web server (e.g apache) .. the php script handles the request..
php script updates where the user is in the world.. (database)

Then i started thinking.. a npc that walks around.. doesnt actually walk around until the user interacts with the "world", e.g. makes a request.
If you coded logic that made the npc "walk" (e.g random walk function)
.. it would have to wait for a client to request before it walks..

So does this mean that to make the npc move around .. we would have to make the client request an update of "data" each time.. e.g

user client makes a request ..
request activates all mobs that are in town ..
all mobs perform functions attached to them
if mobs' data appear @ where user client is, data is sent back to client..
to simulate new fresh data incoming...

Or would it be better.. if you had a scheduler thread or something.. that makes all mobs in the zone do their stuff like a "real living world" regardless of user interaction.. but is that do-able in php?

Many thoughts running in my mind right now as to how to start coding a php-ajax mud.. if its even possible.. or whether if its even good to try a php-ajax-mud. I wouldn't like to re-invent the wheel either.. but i can't seem to find a php-codebase out there for muds... hmm

Any thoughts?

- ray
Find all posts by this user
Quote this message in a reply
09-26-2009, 12:45 AM
Post: #4
RE: HTTP Streaming testing results
Hi Ray,

In order to have the MUD feel and function like a MUD now, you will definitely need to have all the NPCs 'live' without interaction from the user, otherwise your MUD isn't going to very persistent.

Also, I'm not sure if PHP + Apache can really work in this case give the nature of PHP/Apache/HTTP Protocol and the nature of MUDs. In order for an AJAX Mud to be successful, you need to keep the connection open between the client (the user/browser) and the server and constantly stream data back to the client as things change in your world/environment.

If this can be done in PHP, then great, you have a way of coding the UI part. However, a MUD Engine (or driver or kernel or whatever you want to call it) needs to run separately from the PHP code.

To me, these are your options:
- Code a new MUD Engine that will let PHP interact with it
- Modify an existing MUD Engine that will let PHP interact with it
- Skip PHP and modify/create a MUD Engine that returns HTML instead of telnet and acts like a mini Web Server.
Find all posts by this user
Quote this message in a reply
05-24-2010, 12:48 PM
Post: #5
RE: HTTP Streaming testing results
Rollbacks (using gb-trees) and fast-connections are easy to handle in Erlang, which is updated regularly, and works on three major platforms.

As far as the issue of XHR support, and IFRAME memory-usage there is always a third option, if you don't mind dirty hacks. Just create a really-small, transparent flash-window, with a script that acts as a proxy between the server and the client. Then you also get the benefit of using JSON which is more compact.
Quote this message in a reply
05-24-2010, 11:05 PM
Post: #6
RE: HTTP Streaming testing results
(05-24-2010 12:48 PM)York Wrote:  Rollbacks (using gb-trees) and fast-connection are easy to handle in Erlang, which is updated regularly, and works on three major platforms.
Erlang? Never heard of it. Why don't you write a post in the Driver and Engines forum informing us about it? I'd be interested in reading about it.

(05-24-2010 12:48 PM)York Wrote:  As far as the issue of XHR support, and IFRAME memory-usage there is always a third option, if you don't mind dirty hacks. Just create a really-small, transparent flash-window, with a script that acts as a proxy between the server and the client. Then you also get the benefit of using JSON which is more compact.
I think future clients are going to eventually have the Flash proxy as a fall-back solution if the other native options are not available. But I think that HTML 5 and the next versions of web browsers are going to include so many more options in terms of transports that it might be a moot-point.
Find all posts by this user
Quote this message in a reply
05-25-2010, 02:26 AM
Post: #7
RE: HTTP Streaming testing results
Why not use an existing library like jQuery to handle data transportation? Then you can encode your output as a JSON object (json_encode) and have jQuery handle it natively.
Find all posts by this user
Quote this message in a reply
05-25-2010, 02:35 AM
Post: #8
RE: HTTP Streaming testing results
In this particular case, it would suffer from the same issue in IE since it would be using IE's XHR and resulting in no event being triggered for ready state 3.

As I played around with different techniques, I did find that there are better alternatives to the IFRAME within each browser, but they all have to be implemented differently. Remember the idea is to have the content stream back to the client and not have the client polling the server too much within a single second or minute.
Find all posts by this user
Quote this message in a reply
05-25-2010, 02:46 AM
Post: #9
RE: HTTP Streaming testing results
Ah, I must admit that I skimmed the post. Essentially you are talking about pushing data to the browser, instead of having the browser request data over and over.

Very interesting approach, and one that I had not considered.

I'll attempt some performance testing on this when I get a chance. Maybe some sort of garbage collection routine can be created to reduce overhead.
Find all posts by this user
Quote this message in a reply
05-25-2010, 07:56 AM
Post: #10
RE: HTTP Streaming testing results
You could always maintain a connection and minimize the overhead. Essentially whenever something changes on the server an extremely small message event is sent to the browser which instructs the browser to poll for updates.

Finally there is always the possibility of using client-side priorities. When a new client connects a session-object is created along with a timer variable which is sent to the client. The timer variable is created so as to overlap as little as possible with the timer variables of other clients.

Each client then starts a count-down starting from the initial value set in their countdown variable. Once the variable reaches zero the client polls for new data. This segregates the client load based on time (who connected first).

Granted I always took issue with the fact that some players had a longer timer then others, so there is a fix to this problem.

Lets say we have three client groups, 'X', 'Y', and 'Z', with timer values of four, six, and eight seconds respectively. suppose the server's maximum allowable connections is 60 (one connection per client, which is rather inefficient for high loads but I will use for the purpose of example).
Each group permits 20 clients. Starting at zero clients any client that connects is placed in group 'X' with a countdown timer of four seconds. Once 'X' is full, new clients will be placed in group 'Y' and likewise for 'Z'.

Each time a client counts down to zero and polls for data, it is placed in the group with the next highest countdown timer. So for example if a particular client is in group 'X', next time it polls for data the client will be placed in group 'Y' and the client-side timer will be set accordingly. If the client is in group 'Z' it will be placed in group 'X'. This minimizes the advantage a client with an older connection would have over a client with a newer connection to the server.

Keep in mind when polling for data, the clients timer value would have to be matched with a server-side timer otherwise some unscrupulous users may get the notion to 'adjust' the timer to their own advantage.
Quote this message in a reply
Post Reply 


Forum Jump:


User(s) browsing this thread: 3 Guest(s)