您的位置:首页 > 理论基础 > 计算机网络

用edas写一个简单的http Server,扩展http协议的处理器

2009-11-11 23:04 495 查看

为了说明一下基础tcp开发库是如何扩展来处理上层协议的,我这里用一个简单到极点的Http Server来作为例子。这个例子会处理发到特定端口的所有http请求,并返回显示Hello world的网页。

由于是一个很简单的例子,所以我们并不需要解析完整的Http协议,当然我们是能够很快构建一个http处理器,毕竟这是一个基于文本行的协议,不过即使这样还是需要很大的篇幅,所以我们只需要处理其中一小部份。

首先我们来看看Http的request。http的请求是一串文本,由多个行组成,每行都是key value形式的,第一行表示了请求的方法和路径,由空格隔开,后面的是请求的头,由冒号隔开,不过其中的内容表示什么意思对我们来说没什么意义,我们在这里也不打算处理,我们把它们存在一个hash表里,等待更高级的处理器来处理。

所以首先我们先建立一个类,实现IProcessor接口:

class HttpProcessor : IProcessor
{
#region IProcessor 鎴愬憳

public void Init(IWorkingSocket Sock)
{
throw new NotImplementedException();
}

public void NextProcessor(IProcessor NextProcessor)
{
throw new NotImplementedException();
}

public void PushData(byte[] Data, int ReadCount)
{
throw new NotImplementedException();
}

#endregion

#region IDisposable 鎴愬憳

public void Dispose()
{
throw new NotImplementedException();
}

#endregion
}
<!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com -->

 

根据前面的分析我们需要在其中用一个HashTable来存储http的请求头信息。

在每一次得到一行数据的时候就分析,是头一行还是header的行。然后将其插入hashtable,如果得到的是一个空行,那么就表明请求结束了,那么我们就将一段html发送回去。

class HttpProcessor : IProcessor
{
private Dictionary<string, string> httpHeader;

public HttpProcessor()
{
httpHeader = new Dictionary<string, string>();
}

public event Action<IWorkingSocket,Dictionary<string, string>> OnRequest;

#region IProcessor 成员

private IWorkingSocket Conn;

public void Init(IWorkingSocket Sock)
{
Conn = Sock;
}

public void NextProcessor(IProcessor NextProcessor)
{
//如果没有下级处理器就留空
}

public void PushData(byte[] Data, int ReadCount)
{
string line = Encoding.ASCII.GetString(Data, 0, ReadCount);
if (line.Equals("\r\n"))
{
if (OnRequest != null)
{
OnRequest(Conn, httpHeader);
}
}
string[] temp = null;
if (line.Split(':').Length>1)
{
temp = line.Split(':');
httpHeader.Add(temp[0], temp[1]);
return;
}
if (line.Split(' ').Length > 1)
{
temp = line.Split(' ');
httpHeader.Add(temp[0], temp[1]);
return;
}
}

#endregion

#region IDisposable 回收资源

public void Dispose()
{
httpHeader.Clear();
Conn = null;
}
#endregion
}
<!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com -->

 

ok,这样子后我们在处理OnRequest事件的时候就能够接收到一个Dictionary对象,里面就是所有http的头信息,如果我们不关系其中的内容就可以直接在这个事件里返回数据了。

最后的结果:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using org.Alexander.EDAS;

namespace EdasServer
{
class Program
{
static void Main(string[] args)
{
Acceptor acp = new Acceptor(8888);
acp.OnError = (ex, str) =>
{
//TO DO:To handle listenner's error
};
acp.Accepted = (sock,id,buffersize) =>
{
AsyncSocket sk = new AsyncSocket(sock, buffersize);
sk.ID = id;
sk.OnError += new Action<Exception, string>(sk_OnError);
sk.Disconnected += new Action<long>(sk_Disconnected);
TokenProcessor Proc = new TokenProcessor(0x0A);
sk.Processor = Proc;
HttpProcessor httpProc = new HttpProcessor();
httpProc.OnRequest += new Action<IWorkingSocket, Dictionary<string, string>>(httpProc_OnRequest);
Proc.NextProcessor(httpProc);
sk.WaitReceive();
};
acp.WaitAsyncAccept();
Console.ReadKey();
}

static void httpProc_OnRequest(IWorkingSocket arg1, Dictionary<string, string> arg2)
{
StringBuilder html=new StringBuilder();
html.Append("<HTML><HEAD><TITLE>test</TITLE></HEAD><BODY><H3>Hello world</H3></BODY></HTML>");
StringBuilder str = new StringBuilder();
str.Append("HTTP /1.1 200 OK\r\n");
str.Append("Date:" + DateTime.Now.ToLongDateString()+"\r\n");
str.Append("Server: Edas Server(win32)\r\n");
str.Append("Content-Length: " + html.Length+"\r\n");
str.Append("Content-Type: text/html\r\n");
string Data = str.ToString() + "\r\n" + html.ToString();
arg1.SendToQueue(Encoding.ASCII.GetBytes(Data));
arg1.Disconnect();
}
static void sk_Disconnected(long obj)
{
//TO DO:To handle disconnect event
}
static void Proc_OnLine(IWorkingSocket arg1, byte[] arg2)
{
arg1.SendToQueue(arg2);
}
static void sk_OnError(Exception arg1, string arg2)
{
//TO DO:Process errors
}
}

class HttpProcessor : IProcessor
{
private Dictionary<string, string> httpHeader;

public HttpProcessor()
{
httpHeader = new Dictionary<string, string>();
}

public event Action<IWorkingSocket,Dictionary<string, string>> OnRequest;

#region IProcessor 鎴愬憳

private IWorkingSocket Conn;

public void Init(IWorkingSocket Sock)
{
Conn = Sock;
}

public void NextProcessor(IProcessor NextProcessor)
{
//濡傛灉鏆傛椂娌℃湁涓嬬骇澶勭悊鍣ㄧ殑鏃跺€欑暀绌?
}

public void PushData(byte[] Data, int ReadCount)
{
string line = Encoding.ASCII.GetString(Data, 0, ReadCount);
if (line.Equals("\r\n"))
{
if (OnRequest != null)
{
OnRequest(Conn, httpHeader);
}
}
string[] temp = null;
if (line.Split(':').Length>1)
{
temp = line.Split(':');
httpHeader.Add(temp[0], temp[1]);
return;
}
if (line.Split(' ').Length > 1)
{
temp = line.Split(' ');
httpHeader.Add(temp[0], temp[1]);
return;
}
}

#endregion

#region IDisposable 鎴愬憳

public void Dispose()
{
httpHeader.Clear();
Conn = null;
}
#endregion
}
}
<!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com -->

运行后,打开IE,输入 http://localhost:8888,得到结果如下:

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: