RTMP (Real-Time Messaging Protocol) is a binary protocol supported by Flash Player which enables fast, efficient, bidirectional communication between Flex/Flash clients and server-side applications. The protocol supports data messaging for various message exchange paradigms (client-to-client(s), client-to-server, server-to-client(s) and server-to-server) as well as media (video and audio) streaming and recording. WebORB for .NET supports the RTMP protocol and provides facilities to enable data message exchanges mentioned above as well as video streaming and recording. This articles describes the setup, configuration and APIs for implementing a data push from the .NET code to all connected clients.
To get started make sure you have the following software installed:
To demonstrate server-to-client data push over RTMP, the article will use a Flex application which displays a chart of the server's CPU allocation. The CPU readings will be read by .NET code and delivered to the client using WebORB's Messaging (RTMP) infrastructure. The diagram below illustrates the process:

Project development will consist of two parts:
WebORB Messaging infrastructure has an abstraction of 'application handler'. An application handler represents a messaging application also referred to as application scope. When a client connects to the server, it must specify the application by name. Application scope shares all the context managed within the application, provides access to all the client connections and shared objects. The code below is the application handler for the CPU Monitoring example reviewed in this article:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Diagnostics;
6: using System.Timers;
7:
8: using Weborb.Messaging.Api.Service;
9: using Weborb.Messaging.Api;
10: using Weborb.Messaging.Server.Adapter;
11:
12: namespace CPUMonitor
13: {
14: public class CPUMonitoringAppHandler : ApplicationAdapter
15: {
16: private Timer cpuReadingTimer;
17: private PerformanceCounter cpuCounter;
18:
19: // invoked when WebORB for .NET starts up
20: public override bool appStart( IScope app )
21: {
22: bool appStarted = base.appStart( app );
23:
24: // if application could not start for any reason, do not proceed further
25: if( !appStarted )
26: return appStarted;
27:
28: // initialize performance counter
29: cpuCounter = new PerformanceCounter();
30: cpuCounter.CategoryName = "Processor";
31: cpuCounter.CounterName = "% Processor Time";
32: cpuCounter.InstanceName = "_Total";
33:
34: // start thread to get CPU readings
35: cpuReadingTimer = new Timer( 1000 );
36: cpuReadingTimer.Elapsed += new ElapsedEventHandler( cpuReadingTimer_Elapsed );
37: return appStarted;
38: }
39:
40: void cpuReadingTimer_Elapsed( object sender, ElapsedEventArgs e )
41: {
42: // ignore timer event, if there are no connected clients to the scope
43: if( scope.getClients().Count == 0 )
44: return;
45:
46: // get the CPU reading
47: float cpuUtilization = cpuCounter.NextValue();
48:
49: // create an array of values to deliver to the client.
50: // there is only one value, but the API requires it to be an array
51: object[] args = new object[] { cpuUtilization };
52:
53: // get an enumeration of connections to this application
54: IEnumerator<IConnection> connections = scope.getConnections();
55:
56: while( connections.MoveNext() )
57: {
58: IConnection connection = connections.Current;
59:
60: // invoke client-side function to deliver CPU reading
61: if( connection is IServiceCapableConnection )
62: ((IServiceCapableConnection) connection).invoke( "processCPUReading", args );
63: }
64: }
65: }
66: }
The CPUMonitoringAppHandler class is the application handler for the messaging application. The class must extend the ApplicationAdapter class. (The base class is in the Weborb.Messaging.Server.Adapter namespace). CPUMonitoringAppHandler declares and creates a timer (lines 16 and 35-36). The timer wakes up every second and checks if the application has any connected clients (line 43). If there is at least one client, the timer event gets the latest CPU reading using PerformanceMonitor API (line 47) and subsequently delivers the reading value to all connected clients (lines 54-63).
The handler class can be compiled as a class library and deployed into the default WebORB installation folder. See the "Introduction to Flex and .NET integration" article for the deployment instructions. You can also download a Visual Studio solution with the source code for the .NET part of the project (make sure to add a project reference to weborb.dll).
Once the assembly with the application handler is deployed, it must be registered as a messaging application. The instructions below describe the process:
Using Flash Builder create a Flex project as described in the "Introduction to Flex and .NET integration" article. If you are using Flex Builder, see the "Setting up Flex Builder to work with WebORB" article for the instructions on how to create and configure a Flex project to work with WebORB.
Consider the MXML/ActionScript code below:
1: <?xml version="1.0" encoding="utf-8"?>
2: <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
3: xmlns:s="library://ns.adobe.com/flex/spark"
4: xmlns:mx="library://ns.adobe.com/flex/halo"
5: creationComplete="init()">
6: <fx:Declarations>
7: </fx:Declarations>
8: <fx:Script>
9: <![CDATA[
10: import mx.collections.ArrayCollection;
11: import mx.controls.Alert;
12:
13: [Bindable]
14: private var cpuValues:ArrayCollection = new ArrayCollection();
15: private var serverConnection:NetConnection;
16:
17: private function init():void
18: {
19: serverConnection = new NetConnection();
20: serverConnection.addEventListener(NetStatusEvent.NET_STATUS, handleStatus );
21: serverConnection.client = this;
22: serverConnection.connect( "rtmp://localhost:2037/CPUMonitoringApp" );
23:
24: for( var i:int = 0; i < 100; i++ )
25: cpuValues.addItem( 0 );
26: }
27:
28: private function handleStatus( evt:NetStatusEvent ):void
29: {
30: switch( evt.info.code )
31: {
32: case "NetConnection.Connect.Success":
33: break;
34: case "NetConnection.Connect.Failed":
35: Alert.show( "Unable to connect to WebORB", "Connection Error" );
36: break;
37: }
38: }
39:
40: public function processCPUReading( cpuUtilization:Number ):void
41: {
42: // create sliding chart effect
43: cpuValues.removeItemAt( 0 );
44: cpuValues.addItem( cpuUtilization );
45: }
46: ]]>
47: </fx:Script>
48: <s:Panel left="5" right="5" top="5" bottom="5"
49: title="Server CPU Utilization">
50: <mx:LineChart id="cpuChart"
51: left="10" right="10" top="10" bottom="10"
52: dataProvider="{cpuValues}">
53: <mx:series>
54: <mx:LineSeries displayName="CPU(%)" yField=""/>
55: </mx:series>
56: </mx:LineChart>
57: </s:Panel>
58: </s:Application>
The client code uses the NetConnection API to connect to the server and receive server-to-client (DataPush) callbacks. The "serverConnection" variable is declared on line 15 and initialized on lines 19-22. Notice the URL of the messaging application on line 22. The "CPUMonitoringApp" part of the URL refers to the messaging application created earlier in the article. It is also important to note the assignment on line 21. The "client" property on NetConnection refers to the object which contains the methods invoked from the server-side. In this example, the same object (the Flex application itself) hosts the method invoked on the server. The method is "processCPUReading" (lines 40-45). The method receives an argument value delivered by the server. The value is stored in a bindable ArrayCollection - variable "cpuValues". The chart (lines 50-56) uses cpuValues as the data provider. As soon as the code updates the values in the array collection, the chart is automatically updated.
Download full MXML listing of the example.
When you run the example, you should immediately see data in the chart. You can try running multiple browsers with the example application. If the data does not arrive, make sure the WebORB messaging server is running - you can do that by opening the WebORB Management Console.
