I wanted to set up a simple interface to serve information online without having to install a bunch of stuff and read through a bunch of documentation about configuration. I came up with a class and an interface in c# that should simplify/standardize some of my other projects.
The handler interface provides access to the request and response streams for each request
interface IRequestHandler
{ //same idea as a java servlet
void handle(HttpListenerContext context);
}
Here is a simple single threaded server; requests block while processing. There are performance issues here if you intend to have your request handler doing any heavy lifting, but for doing something like processing a get request and sending/receiving some stuff on a serial port it gets the job done. This implementation can always be swapped out, what matters is giving my IRequestHandlers something to run from.
class Server
{
protected HttpListener httpListener;
protected IRequestHandler requestHandler;
//path is something like http://localhost:8000/
public Server(string path, IRequestHandler requestHandler)
{
this.requestHandler = requestHandler;
httpListener = new HttpListener();
httpListener.Prefixes.Add(path);
}
public void begin()
{
//does not return until server dies
httpListener.Start();
while (true)
{
HttpListenerContext context = httpListener.GetContext();
requestHandler.handle(context);
}
}
}
To get an idea how to put the IRequestHandler to use I wrote a (hopefully) self-explanatory example. I havn't used this in any long running programs, so hopefully calling OutputStream.close() is all I have to do to properly kill the HttpListenerContext.
class SimpleHandler
{
public void handle(HttpListenerContext context)
{
byte[] bytes = Encoding.ASCII.GetBytes("hello world");
context.Response.OutputStream.Write(bytes, 0, bytes.Length);
context.Response.OutputStream.Close();
}
}
This is a little more useful for serving up static content.
class StaticDataHandler : ServerFramework.IRequestHandler
{
private byte[] data;
public StaticDataHandler(string dataString)
{
data = Encoding.ASCII.GetBytes(dataString);
}
public StaticDataHandler(byte[] dataBytes)
{
data = dataBytes;
}
public void handle(HttpListenerContext context)
{
context.Response.OutputStream.Write(data, 0, data.Length);
context.Response.OutputStream.Close();
}
}
And here is how you would serve a couple static pages, the idea is to run one server per page.
class MyProgram
{
static void Main(string[] args)
{
//make the handler objects
IRequestHandler pageHandler0 = new StaticDataHandler("this is page 1");
IRequestHandler pageHandler1 = new StaticDataHandler("this is page 2");
//make the server objects
ServerFramework.Server server0 = new ServerFramework.Server("http://localhost:8000/foo/", pageHandler0);
ServerFramework.Server server1 = new ServerFramework.Server("http://localhost:8000/bar/", pageHandler1);
//start the servers in threads; Server.begin blocks forever
Thread threadedserver0 = new Thread(server0.begin);
Thread threadedserver1 = new Thread(server1.begin);
threadedserver0.Start();
threadedserver1.Start();
threadedserver0.Join();
threadedserver1.Join();
}
}