I am wanting to make a TCP server that listens on port 443 so that it can receive HTTP requests and post back.
Right now I am using Apache & PHP to do this in the normal way, but is it possible to do this without a web server?
For instance I've built out a traditional TCP/IP client/server application in C# .NET. Is it possible to use this implementation to handle the HTTP requests instead of using a web server?
This project may help you to create a web server from scratch: MiniHttpd: an HTTP web server library using pure TCP/IP
But instead of dealing with many unnecessary details such as parsing headers, compression, authentication, ssl etc. I would use the built-in HttpListener class.
Here is a simplified(but working) multi-threaded WebServer
void CreateWebServer()
{
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://*:8080/");
listener.Start();
new Thread(
() =>
{
while (true)
{
HttpListenerContext ctx = listener.GetContext();
ThreadPool.QueueUserWorkItem((_) => ProcessRequest(ctx));
}
}
).Start();
}
void ProcessRequest(HttpListenerContext ctx)
{
string responseText = "Hello";
byte[] buf = Encoding.UTF8.GetBytes(responseText);
Console.WriteLine(ctx.Request.Url);
ctx.Response.ContentEncoding = Encoding.UTF8;
ctx.Response.ContentType = "text/html";
ctx.Response.ContentLength64 = buf.Length;
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
ctx.Response.Close();
}
EDIT
I changed the server a little bit to make it host a RESTful WebService (MyService
). It returns the the result as Json. You can call it as http://localhost:8080/?method=Calc&i=5&j=4
(I omitted many error checks for simplicity)
public class MyService
{
public Result Calc(int i, int j)
{
return new Result() { Addition = i + j, Multiplication = i * j };
}
}
public class Result
{
public int Addition { set; get; }
public int Multiplication { set; get; }
}
void CreateWebServer()
{
MyService service = new MyService();
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://*:8080/");
listener.Start();
new Thread(
() =>
{
while (true)
{
HttpListenerContext ctx = listener.GetContext();
ThreadPool.QueueUserWorkItem((_) => ProcessRequest(ctx,service));
}
}
).Start();
}
void ProcessRequest(HttpListenerContext ctx,MyService service)
{
try
{
string responseText = Execute(ctx, service);
byte[] buf = Encoding.UTF8.GetBytes(responseText);
ctx.Response.ContentEncoding = Encoding.UTF8;
ctx.Response.ContentType = "application/json";
ctx.Response.ContentLength64 = buf.Length;
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
}
catch
{
ctx.Response.StatusCode = (int) HttpStatusCode.NotFound;
}
ctx.Response.Close();
}
string Execute(HttpListenerContext ctx, MyService service)
{
System.Collections.Specialized.NameValueCollection nv = HttpUtility.ParseQueryString(ctx.Request.Url.Query);
MethodInfo mi = service.GetType().GetMethod(nv["method"]);
object[] parameters = mi.GetParameters()
.Select(pi => Convert.ChangeType(nv[pi.Name], pi.ParameterType))
.ToArray();
return JsonConvert.SerializeObject(mi.Invoke(service, parameters));
}
At the lowest level, you can do this using an HTTP Listener Class.
http://geekswithblogs.net/Nitin/archive/2008/06/22/using-the-http-listener-class.aspx
I wrote something similar as a uni project once, so I can look for the code if you have any particular questions.
If you want to go higher-up you might look into web services.
Here's part of my code...see what you can do with it. :
IPAddress address = IPAddress.Parse("127.0.0.1");
IPEndPoint port = new IPEndPoint(address, 9999); //port 9999
TcpListener listener = new TcpListener(port);
listener.Start();
Console.WriteLine("--Server loaded--");
while (true) //loop forever
{
Console.WriteLine("Waiting for New Client");
Socket sock = listener.AcceptSocket();
byte[] buffer = new byte[32];
string incomingMessage="";
//read:
while (sock.Available > 0)
{
int gotBytes = sock.Receive(buffer);
incomingMessage += Encoding.ASCII.GetString(buffer, 0, gotBytes);
}
//debugging:
//Console.WriteLine(incomingMessage);
//Now check whether its a GET or a POST
if (incomingMessage.ToUpper().Contains("POST") && incomingMessage.ToUpper().Contains("/DOSEARCH")) //a search has been asked for
{
Console.WriteLine("Query Has Been Received");
//extracting the post data
string htmlPostData = incomingMessage.Substring(incomingMessage.IndexOf("songName"));
string[] parameters = htmlPostData.Split('&');
string[] inputs = new string[5];
for (int i=0; i<parameters.Length; i++)
{
inputs[i] = (parameters[i].Split('='))[1];
inputs[i] = inputs[i].Replace('+',' ');
}
...
byte[] outbuffer = Encoding.ASCII.GetBytes(answerPage.ToString());
sock.Send(outbuffer);
Console.WriteLine("Results Sent");
sock.Close();