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
- Download the AIR 2.0 beta runtime here.
- Download MiniAIRWebServer.air here.
- 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>

18 Comments
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!!
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..
I produced “airhttpd” is a HTTP server by AIR 2.0 too.
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!
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
@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
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
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
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….)
Solution
Use AIR2Beta sdk. Air2Beat2 sdk doesnt work.
To solve the issue (ServerSocketConnectEvent )
use Air2Beta1 instead of Air2Beat2.
Congratulations for the excellent sample =)
5 Trackbacks
[...] -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 [...]
[...] AIR 2.0 Web Server using the New Server Socket API (from Christophe Coenraets) [...]
[...] 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 [...]
[...] Christophe Coenraets – AIR 2 Web Server using SocketServer API [...]
[...] 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( [...]