AIR 2.0 Web Server using the New Server Socket API

After exploring Java integration using the new Native Process API (here and here), Excel integration using the new file.openWithDefaultApplication(), and the new Microphone API, here is another application I wrote, this time to explore the new Adobe AIR 2.0 Server Socket API.

The “Mini AIR Web Server” is a simplistic implementation of an HTTPServer. Needless to say that it is far from being a production quality Web Server. The goal here is simply to use the well understood mechanics of a web server to learn how to use server sockets in AIR 2.0.

Installation Instructions

  1. Download the AIR 2.0 beta runtime here.
  2. Download MiniAIRWebServer.air here.
  3. Double-click MiniAIRWebServer.air in Explorer or Finder to start the installation process.

To test the application, open a browser and test the sample HTML pages provided with the application:

NOTE: You may have to change the port number in these URLs depending on the port number you enter in the application.

You can add your own content in the webroot folder in the applicationStorageDirectory.

View Source is enabled, but if you just want to take a quick peak at the code, here is MiniAIRWebServer.mxml:

<?xml version="1.0" encoding="utf-8"?>
<!-- Author: Christophe Coenraets http://coenraets.org -->
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
					   xmlns:s="library://ns.adobe.com/flex/spark"
					   xmlns:mx="library://ns.adobe.com/flex/halo"
					   title="Mini AIR Web Server"
					   applicationComplete="init()" viewSourceURL="srcview/index.html">
	<s:layout>
		<s:VerticalLayout paddingTop="8" paddingLeft="8" paddingRight="8" paddingBottom="8"/>
	</s:layout>

	<fx:Script>
		<![CDATA[
			import flash.events.Event;
			import flash.events.ProgressEvent;
			import flash.events.ServerSocketConnectEvent;
			import flash.net.ServerSocket;
			import flash.net.Socket;
			import flash.utils.ByteArray;
			import mx.controls.Alert;

			private var serverSocket:ServerSocket;

			private var mimeTypes:Object = new Object();

			private function init():void
			{
				// The mime types supported by this mini web server
				mimeTypes[".css"] 	= "text/css";
				mimeTypes[".gif"] 	= "image/gif";
				mimeTypes[".htm"] 	= "text/html";
				mimeTypes[".html"] 	= "text/html";
				mimeTypes[".ico"] 	= "image/x-icon";
				mimeTypes[".jpg"] 	= "image/jpeg";
				mimeTypes[".js"] 	= "application/x-javascript";
				mimeTypes[".png"] 	= "image/png";

				// Initialize the web server directory (in applicationStorageDirectory) with sample files
				var webroot:File = File.applicationStorageDirectory.resolvePath("webroot");
				if (!webroot.exists)
				{
					File.applicationDirectory.resolvePath("webroot").copyTo(webroot);
				}
			}

			private function listen():void
			{
				try
				{
					serverSocket = new ServerSocket();
					serverSocket.addEventListener(Event.CONNECT, socketConnectHandler);
					serverSocket.bind(Number(port.text));
					serverSocket.listen();
					log.text += "Listening on port " + port.text + "...\n";
				}
				catch (error:Error)
				{
					Alert.show("Port " + port.text +
						" may be in use. Enter another port number and try again.\n(" +
						error.message +")", "Error");
				}
			}

			private function socketConnectHandler(event:ServerSocketConnectEvent):void
			{
				var socket:Socket = event.socket;
				socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
			}

			private function socketDataHandler(event:ProgressEvent):void
			{
				try
				{
					var socket:Socket = event.target as Socket;
					var bytes:ByteArray = new ByteArray();
					socket.readBytes(bytes);
					var request:String = "" + bytes;
					log.text += request;
					var filePath:String = request.substring(4, request.indexOf("HTTP/") - 1);
					var file:File = File.applicationStorageDirectory.resolvePath("webroot" + filePath);
					if (file.exists && !file.isDirectory)
					{
						var stream:FileStream = new FileStream();
						stream.open( file, FileMode.READ );
						var content:ByteArray = new ByteArray();
						stream.readBytes(content);
						stream.close();
						socket.writeUTFBytes("HTTP/1.1 200 OK\n");
						socket.writeUTFBytes("Content-Type: " + getMimeType(filePath) + "\n\n");
						socket.writeBytes(content);
					}
					else
					{
						socket.writeUTFBytes("HTTP/1.1 404 Not Found\n");
						socket.writeUTFBytes("Content-Type: text/html\n\n");
						socket.writeUTFBytes("<html><body><h2>Page Not Found</h2></body></html>");
					}
					socket.flush();
					socket.close();
				}
				catch (error:Error)
				{
					Alert.show(error.message, "Error");
				}
			}

			private function getMimeType(path:String):String
			{
				var mimeType:String;
				var index:int = path.lastIndexOf(".");
				if (index > -1)
				{
					mimeType = mimeTypes[path.substring(index)];
				}
				return mimeType == null ? "text/html" : mimeType; // default to text/html for unknown mime types
			}

		]]>
	</fx:Script>

	<s:HGroup verticalAlign="middle">
		<s:Label text="Port:"/>
		<s:TextInput id="port" text="8888" width="50"/>
		<s:Button label="Listen" click="listen()"/>
	</s:HGroup>

	<s:TextArea id="log" width="100%" height="100%" />

</s:WindowedApplication>

39 Responses to AIR 2.0 Web Server using the New Server Socket API

  1. Francis Varga December 7, 2009 at 4:23 pm #

    Holy shit very very nice… Thx for this little snippet!

  2. Palleas December 7, 2009 at 5:10 pm #

    This is awesome, I just love it!

  3. Elliot Rock December 7, 2009 at 5:17 pm #

    nice solution.

    But the pink code hurt my eyes!!

  4. Gary Mc December 7, 2009 at 8:22 pm #

    Awesome! Now if there was a way for AIR to know when a file changes (I guess it could just poll) then an AIR app could be built for providing a live preview when developing in HTML/CSS/Javascript. Given a folder and HTML file, it could serve the page etc with the above, show the page with the AIR browser, and as soon as a file changes in the folder, refresh the browser!

  5. Devaraj December 9, 2009 at 2:54 am #

    Just Great..

  6. tilfin December 17, 2009 at 7:49 am #

    I produced “airhttpd” is a HTTP server by AIR 2.0 too.

  7. Gaurav December 22, 2009 at 11:56 pm #

    Great Work Christophe. However, this comment is mostly a request. Since, you work at Adobe, I would like you to please convince them to create a robust FTP class in AIR2 so that we don’t have to fiddle with sockets. I am an AIR+AJAX developer and sockets are a pain. I am not able to successfully implement an FTP functionality in my AIR app as I have to go through the sockets in detail. It would be a great help to all.

    Thanks, Gaurav

  8. Barbara December 28, 2009 at 3:54 am #

    Thank for the snippets!

  9. James Burke Hubbard January 2, 2010 at 6:20 pm #

    Christophe,

    When I try to compile your source in Flash Builder Beta 2, I get a unspecified error at this socket function.

    private function socketConnectHandler(event:ServerSocketConnectEvent):void

    I would appreciate any insight you might have.

    Are you able to publish your working project file so that we could start from a known working point.

    Outstanding tutorial, thanks for the fantastic work.

    Cheers,

    James

  10. Nathan January 3, 2010 at 12:40 am #

    @James,

    Yeah, same problem with me too… the problem could be found in line 65:

    private function socketConnectHandler(event:ServerSocketConnectEvent):void
    {
    var socket:Socket = event.socket;
    socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
    }

    with the following error message:

    “Type was not found or was not a compile-time constant: ServerSocketConnectEvent.”

    This would be very useful if you can provide us with a solution for this, so we can compile it in our end.

    Thanks a lot Christophe for another great AIR application!

    Nathan

  11. Brian Moran January 14, 2010 at 2:47 pm #

    Any performance improvements in the overall socket library with 2.0?

    With the 1.5 runtime, socket sends of large buffers (1MB) seems to be limited to 100KBytes/second regardless of what the link and endpoint can do. Equivalent code in other interpreted run time environments can go 10-15 times faster.

  12. sharedtut January 21, 2010 at 11:40 pm #

    thank you so much for showing the source code

  13. Derrick January 25, 2010 at 11:12 am #

    Christophe,
    This is pretty awesome! If AS3 had some sort of dynamic AS3 evaluation, someone could write a web server which could execute server side AS3! There are a libraries out there, but it would be pretty slow, since they interpret/run the script.

    I hope that AIR gets some scripting engine support in the future, with JIT compilation, etc!

    - Derrick

  14. Keshaw January 25, 2010 at 1:35 pm #

    @James, @Nathan

    Same problem with me too

    private function socketConnectHandler(event:ServerSocketConnectEvent):void
    {
    var socket:Socket = event.socket;
    socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
    }

    Any body got the solutions?

    Christophe Could you provide me the published project code?

    Thanks in advance

  15. who January 29, 2010 at 4:38 am #

    I have solved the problem:
    “Type was not found or was not a compile-time constant: ServerSocketConnectEvent.”

    I download the AIR 2.0 SDK

    and follow this document:
    http://labs.adobe.com/wiki/index.php/AIR_2:Release_Notes#How_to_overlay_the_Adobe_AIR_SDK_for_use_with_the_Flex_SDK

    It is work.

    (sorry, my english is not good, if you dont know what I say, I’m so sorry….)

  16. Sreejith March 5, 2010 at 10:23 am #

    Solution

    Use AIR2Beta sdk. Air2Beat2 sdk doesnt work.

  17. GOD March 5, 2010 at 10:27 am #

    To solve the issue (ServerSocketConnectEvent )
    use Air2Beta1 instead of Air2Beat2.

  18. Leonardo França June 18, 2010 at 11:20 am #

    Congratulations for the excellent sample =)

  19. zokii October 7, 2010 at 9:10 am #

    hi, i have problem with this code..
    it show error wtih this line -> private function onConnect(e:ServerSocketConnectEvent):void

  20. S October 11, 2010 at 12:16 pm #

    Hi Christopher, I used your inspiring tutorial to create a mp3 server, which serves songs to Android, and it’s working amazingly well on Windows 7, Linux and OSX machines.

    However Windows XP and Vista users are experiencing a very strange error, all the mp3′s served are cut off after only a few seconds of playing,, and I receive a SoundChannel.COMPLETE event.

    This has nothing to do with the client, as I can load the mp3 file from the server, in my web browser and observe exactly the same thing?

    I am passing the proper mime-type, and content-length headers.

    I also have issue sending a compressed byteArray over the socket, it can never be decompressed client side, however I’ve verified the dat file on the server is perfectly fine, so something is getting screwed up during transmition. Again, very small subset of users are experiencing this…

    Any idea? I’m going crazy over here…

  21. Ben Arent October 26, 2010 at 6:13 am #

    Hi Chris,

    Thanks for posting this. I have been using Serial servers for years to create a connection between apps and Air. This little web server was enough to get me working on a full refactoring and removing of external JAVA TCP/IP Clients.

    Keep on blogging!

    Ben

  22. Shawn November 2, 2010 at 12:38 pm #

    Just a quick follow up on my issues, it was all caused by calling socket.close() after my flush(). (I don’t know why I was doing this in the first place)

    In Win7 and OSX this works fine, but on XP/Vista this will kill the urlStream, It’s almost as though flush() is async in XP/Vista and syncronous in the others…?

    Either way, just leave the socket open and it works great!

  23. Vik June 15, 2011 at 7:00 pm #

    This is a wonderful example. However, I’m trying to develop peer to peer games for mobile devices that can communicate with each other directly on a network (with their local IP block) for WiFi games.

    ServerSocket is not available for mobile device AIR.

    I am not finding any alternatives that will allow one Android pad or iPad to be the game host and allow others to connect into the game for multiplayer fun.

  24. Abraham May 24, 2012 at 12:43 am #

    This is amazing! Works great.

    I am wondering if could work for Air mobile in iPhone and Android??

    Is that posible??

  25. Abraham Pineda October 16, 2012 at 9:12 pm #

    It’s just amazing just what I need. But I am wondering how many user can be supported at once. Is there a number??

  26. Serwery Windows September 23, 2013 at 5:43 am #

    Good post. I learn something new and challenging on blogs I stumbleupon on a daily
    basis. It’s always interesting to read through articles from other authors and use something
    from their sites.

  27. Michal October 24, 2013 at 9:49 am #

    I dont get why in order to process data we need to close(); socket. I wish my server app had a way to tell how many users are online and identify them by some unique id like session ID in php.

  28. Sanny Jane Yacapin December 1, 2013 at 5:13 pm #

    This blog tackles about error code issue of a socket. I hope it would help you in the future.Thank you.

  29. Hello there, just became aware of your blog through Google,
    and found that it’s truly informative. I’m going to watch out for brussels.
    I will be grateful if you continue this in future.

    Lots of people will be benefited from your writing.
    Cheers!

  30. Web Hosting Argentina June 3, 2014 at 4:32 pm #

    Your way of explaining all in this piece of writing is really pleasant, every one be capable of effortlessly know it,
    Thanks a lot.

Trackbacks/Pingbacks

  1. AIR 2.0 Experimente » GELB der Powerflasher Blog - December 9, 2009

    [...] -AIR 2.0 Web Server using the New Server Socket API -Screenrecording app with AIR 2.0 Beta -Embedding Tomcat and BlazeDS in an AIR 2.0 Application -Tomcat Launcher: Sample Application using the AIR 2.0 Native Process API – “Open in Excel”: Another AIR 2 Mini Sample -Voice Notes: Record Voice Notes and Persist them in SQLite with AIR 2 [...]

  2. Flex Monkey Patches » Blog Archive » Rubbernecker’s Review – Chapter2 – Episode3 – (Adobe Flex/Flash/AIR/LCDS Blog post recap) - December 14, 2009

    [...] AIR 2.0 Web Server using the New Server Socket API (from Christophe Coenraets) [...]

  3. AIR 2.0 HTTP Web Server | Promethe's Blog - December 17, 2009

    [...] of this new and incredible ability, Christophe Coenraets posted a small but yet very powerful code snippet to build an HTTP web server using AIR 2.0! Categories: AIR, Flash Tags: ActionScript 3.0, AIR, AIR 2.0, experiment, Flash, RIA [...]

  4. AIR 2 / Flash Player 10.1 Beta Info « Devgirl’s Weblog - December 21, 2009

    [...] Christophe Coenraets – AIR 2 Web Server using SocketServer API [...]

  5. Air 2.0 - Socket.bind() - Flashforum - January 25, 2010

    [...] so server zeugs auszutesten. Creating a socket server in Adobe AIR 2 | Adobe Developer Connection AIR 2.0 Web Server using the New Server Socket API httpeek – Project Hosting on Google Code Dummerweise versagen bei mir aber sowohl Klassen( [...]

  6. Summer AIR Mobile Contest 2010 CZ/SK — FlashRealtime.com - October 6, 2010

    [...] HTML, HTML5, CSS, and JavaScript in AIR 2? – Read HTML Developer’s Guide for Adobe AIR – Read AIR 2.0 Web Server using the New Server Socket API – Read Using the AIR 2 NativeProcess API to create a screen [...]

  7. Introducing EasyIPA | Struct.ca - March 30, 2011

    [...] Sockets are an oft-forgotten feature of Adobe AIR that let you create HTTP servers. This great article by Chrisophe Coenraets is a solid primer on how it’s done. The ability to write a *cross-platform* web server in [...]

  8. PHP in AIR met Native Processes - May 3, 2011

    [...] Een van deze features is de ServerSocket class, een erg krachtige tool om bijvoorbeeld je eigen webserver te bouwen. Maar snel nadat ik had gelezen over ServerSockets, ontdekte ik een andere en misschien [...]

  9. http server in air #2 - Flashforum - March 26, 2012

    [...] [...]

Leave a Reply