⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 使用c#开发自己的web服务器 .txt

📁 c# 大量的学习资料。包括ado.net学习笔记
💻 TXT
📖 第 1 页 / 共 2 页
字号:
使用C#开发自己的web服务器  
 


摘要

 
 
 
这篇文章讨论了如何使用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 GetLocalPath(string sMyWebServerRoot, string sDirName)
  {
  treamReader sr;
  String sLine = "";
  String sVirtualDir = ""; 
  String sRealDir = "";
  intiStartPos = 0;
  //删除多余的空格
  sDirName.Trim();
  // 转换成小写
  sMyWebServerRoot = sMyWebServerRoot.ToLower();
  // 转换成小写
  sDirName = sDirName.ToLower();
  try
  {
  //打开Vdirs.dat文件,获得虚拟目录
  sr = new StreamReader("data\\VDirs.Dat");
  while ((sLine = sr.ReadLine()) != null)
  {
  //删除多余的空格
  sLine.Trim();
  if (sLine.Length > 0)
  {
  //找到分割符
  iStartPos = sLine.IndexOf(";");
  // 转换成小写
  sLine = sLine.ToLower();
  sVirtualDir = sLine.Substring(0,iStartPos);
  sRealDir = sLine.Substring(iStartPos + 1);
  if (sVirtualDir == sDirName)
  {
  break;
  }
  }
  }
  }
  catch(Exception e)
  {
  Console.WriteLine("An Exception Occurred : " + e.ToString());
  }
  if (sVirtualDir == sDirName)
  return sRealDir;
  else
  return "";
  }
  我们还必须使用用户提供的文件扩展名确定Mime类型。
  public string GetMimeType(string sRequestedFile)
  {
  StreamReader sr;
  String sLine = "";
  String sMimeType = "";
  String sFileExt = "";
  String sMimeExt = "";
  // 转换成小写
  sRequestedFile = sRequestedFile.ToLower();
  int iStartPos = sRequestedFile.IndexOf(".");
  sFileExt = sRequestedFile.Substring(iStartPos);
  try
  {
  //打开Vdirs.dat文件,获得虚拟目录
  sr = new StreamReader("data\\Mime.Dat");
  while ((sLine = sr.ReadLine()) != null)
  {
  sLine.Trim();
  if (sLine.Length > 0)
  {
  //找到分割符
  iStartPos = sLine.IndexOf(";");
  // 转换成小写
  sLine = sLine.ToLower();
  sMimeExt = sLine.Substring(0,iStartPos);
  sMimeType = sLine.Substring(iStartPos + 1);
  if (sMimeExt == sFileExt)
  break;
  }
  }
  }
  catch (Exception e)
  {
  Console.WriteLine("An Exception Occurred : " + e.ToString());
  }
  if (sMimeExt == sFileExt)
  return sMimeType; 
  else
  return "";
  }

下面我们来编写建立和向浏览器(客户端)发送头部信息的函数。 

public void SendHeader( string sHttpVersion, 
  string sMIMEHeader, 
  int iTotBytes, 
  string sStatusCode,
  ref Socket mySocket)
  {
  String sBuffer = "";
  //如果用户没有提供Mime类型,则将其缺省地设置为text/html
  if (sMIMEHeader.Length == 0 )
  {
  sMIMEHeader = "text/html"; // Default Mime Type is text/html
  }
  sBuffer = sBuffer + sHttpVersion + sStatusCode + "\r\n";
  sBuffer = sBuffer + "Server: cx1193719-b\r\n";
  sBuffer = sBuffer + "Content-Type: " + sMIMEHeader + "\r\n";

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -