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 -->
<s:WindowedApplication xmlns:fx=""
					   title="Mini AIR Web Server"
					   applicationComplete="init()" viewSourceURL="srcview/index.html">
		<s:VerticalLayout paddingTop="8" paddingLeft="8" paddingRight="8" paddingBottom="8"/>

			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)

			private function listen():void
					serverSocket = new ServerSocket();
					serverSocket.addEventListener(Event.CONNECT, socketConnectHandler);
					log.text += "Listening on port " + port.text + "...\n";
				catch (error:Error)
				{"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
					var socket:Socket = as Socket;
					var bytes:ByteArray = new ByteArray();
					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(); file, FileMode.READ );
						var content:ByteArray = new ByteArray();
						socket.writeUTFBytes("HTTP/1.1 200 OK\n");
						socket.writeUTFBytes("Content-Type: " + getMimeType(filePath) + "\n\n");
						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>");
				catch (error:Error)
				{, "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


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

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

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

  • This is awesome, I just love it!

  • nice solution.

    But the pink code hurt my eyes!!

  • Gary Mc

    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!

  • Just Great..

  • Pingback: AIR 2.0 Experimente » GELB der Powerflasher Blog()

  • Pingback: Flex Monkey Patches » Blog Archive » Rubbernecker’s Review – Chapter2 – Episode3 – (Adobe Flex/Flash/AIR/LCDS Blog post recap)()

  • Pingback: AIR 2.0 HTTP Web Server | Promethe's Blog()

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

  • Pingback: AIR 2 / Flash Player 10.1 Beta Info « Devgirl’s Weblog()

  • Gaurav

    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

  • Thank for the snippets!

  • James Burke Hubbard


    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.



  • Nathan


    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!


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

  • thank you so much for showing the source code

  • Pingback: Air 2.0 - Socket.bind() - Flashforum()

  • 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

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

  • who

    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:

    It is work.

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

  • Sreejith


    Use AIR2Beta sdk. Air2Beat2 sdk doesnt work.

  • GOD

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

  • Congratulations for the excellent sample =)

  • Pingback: Summer AIR Mobile Contest 2010 CZ/SK —

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

  • S

    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…

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


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

  • Pingback: Introducing EasyIPA |

  • Pingback: PHP in AIR met Native Processes()

  • Vik

    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.

  • Pingback: http server in air #2 - Flashforum()

  • This is amazing! Works great.

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

    Is that posible??

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

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

  • Michal

    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.

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

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

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

  • I came across the same problem where files seem to be cut off at arbitary lengths.

    Although simply not closing the stream does fix the issue in some browsers, its probably not the best solution, because when I tested it with some utilities like WGET they are unable to download because the server is not closing the socket.

    What I did instead was to write some code to write the output in 64k blocks (the 64 k is an arbitary value but was less than the 143k that seemed to be the max that was getting written before the socket closed.

    This seems to work fine, albeit if on some systems the block size of 64 k stil causes problems, you’d need to change this.

    One other option could be to delay closing of the stream e.g. 1 frame, using TweenLite etc.
    But personally Im going with my chunking solution.

    // socket.writeBytes(content);
    var bytesToWrite:int = content.length;
    var offset=0;
    const BLOCK_SIZE:int = 64*1024;
    while (bytesToWrite>0)
    if (bytesToWrite>65536)


  • Following on from my previous solution to this issue.

    There is another possibly better way to do this. There is a progress event which the stream dispatches, and if you use this in conjunction with bytesPending, you can determine when the whole buffer had been written and close it at that point.

    if (
    evt.currentTarget.removeEventListener(evt.type, arguments.callee);// remove this listener


    The only possible issue with this, is the use of the anonymous function, however the arguments.callee code is supposed to get the reference to the anonymous function in order for it to be removed.

    • Filippo Gregoretti

      Thank you.

  • Filippo Gregoretti

    Fantastic. Starting from this idea we managed to fix local html rendering on both Android and iOS.