日期:2011-07-23 浏览次数:20475 次
摘要
这 篇文章讨论了如何使用C#开发一个简单的web服务器应用程序。尽管我们可以使用任何一种支持.NET的编程语言开发,但我选择了C#。本篇文章中的代码 是使用微软的β2版的Visual C# Compiler Version 7.00.9254 [CLR version v1.0.2914]编译通过的,对代码作一些小的改动后,使用β1版也可能编译通过。该web服务器应用程序能够与IIS或其他任何web服务器软件同 时在一台服务器上运行,只要为它指定一个空闲的端口即可。在本篇文章中,我还假定读者对.NET、C#或Visual Basic .Net有一定的了解。
该web服务器应用程序能够向浏览器返回HTML格式的文件,而且支持图像,它不加载嵌入式图像或支持任何一种脚本语言。为了简单起见,我将它开发成一个命令行应用程序。
准备工作
首先,我们需要为这个web服务器应用程序定义一个根文件夹,例如,C:\MyPersonalwebServer,然后在该要根目录下创建一个数据目录,例如,C:\MyPersonalwebServer\Data;最后在数据目录下创建三个文件,例如:
Mimes.Dat
Vdirs.Dat
Default.Dat
Mime.Dat中将包含该web服务器支持的MIME类型,其格式为<扩展名>; ,例如:
.html;text/html
.htm;text/html
.bmp;image/bmp
VDirs.Dat中包含有虚拟目录的信息,格式为; <物理目录>,例如:
/; C:\myWebServerRoot/
test/; C:\myWebServerRoot\Imtiaz\
Default.Dat中包含有虚拟目录中文件的信息,例如:
default.html
default.htm
Index.html
Index.htm
为简单起见,我们将使用文本文件存储所有的信息,但我们也可以使用XML等其他的格式。在开始研究代码之前,我们先来看一下在登录网站时浏览器需要传递的头部信息。
我们以请求test.html为例进行说明。在浏览器的地址栏输入http://localhost:5050/test.html(记住,需要在URL中包括端口号),服务器将得到下面的信息:
〈/DRIVE:\PHYSICALDIR〉
GET /test.html HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*
Accept-Language: en-usAccept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; .NET CLR 1.0.2914)
Host: localhost:5050Connection: Keep-Alive
开始编程
namespace Imtiaz
{
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading ;
class MyWebServer
{
private TcpListener myListener ;
private int port = 5050 ; // 可以任意选择空闲的端口
//生成TcpListener的构建器开始监听给定的端口,它还启动调用StartListen()方法的一个线程
public MyWebServer()
{
try
{
//开始监听给定的端口
myListener = new TcpListener(port) ;
myListener.Start();
Console.WriteLine("Web Server Running... Press ^C to Stop...");
//启动调用StartListen方法的线程
Thread th = new Thread(new ThreadStart(StartListen));
th.Start() ;
}
catch(Exception e)
{
Console.WriteLine("An Exception Occurred while Listening :" +e.ToString());
}
}
我们定义了名字空间,包括应用程序必需的引用,初始化了构建器中的端口,启动了端口监听进程,创建了一个新的线程调用startlisten函数。
我们假设用户没有在URL中提供文件名,在这种情况下我们必须自己确定缺省的文件名,并将它返回给浏览器,就象在IIS中的文档标签中定义缺省的文档那样。
我们已经在default.dat中存储了缺省的文件名,并将文件存储在了数据目录中。GetTheDefaultFileName函数将目录路径作为输入参数,打开default.dat文件,在目录中查找文件,根据是否找到了文件返回文件名或一个空格。
public string GetTheDefaultFileName(string sLocalDirectory)
{
StreamReader sr;
String sLine = "";
try
{
//打开default.dat,获得缺省清单
sr = new StreamReader("data\\Default.Dat");
while ((sLine = sr.ReadLine()) != null)
{
//在web服务器的根目录下查找缺少文件
if (File.Exists( sLocalDirectory + sLine) == true)
break;
}
}
catch(Exception e)
{
Console.WriteLine("An Exception Occurred : " + e.ToString());
}
if (File.Exists( sLocalDirectory + sLine) == true)
return sLine;
else
return "";
}
象在IIS中那样,我们必须将虚拟目录解析为物理目录。在Vdir.Dat中,我们已经存储了实际的物理目录和虚拟目录之间的映像关系。需要记住的是,在任何情况下,文件的格式都是重要的。
public string GetLocalPa