From: http://blog.csdn.net/hyde82/archive/2005/12/01/541258.aspx

一、HTTP协议的作用原理

WWW是以Internet作为传输媒介的一个应用系统,WWW网上最基本的传输单位是Web网页。WWW的工作基于客户机/服务器计算模型,由Web 浏览器(客户机)和Web服务器(服务器)构成,两者之间采用超文本传送协议(HTTP)进行通信。HTTP协议是基于TCP/IP协议之上的协议,是Web浏览器和Web服务器之间的应用层协议,是通用的、无状态的、面向对象的协议。HTTP协议的作用原理包括四个步骤:

连接:Web浏览器与Web服务器建立连接,打开一个称为socket(套接字)的虚拟文件,此文件的建立标志着连接建立成功。

请求:Web浏览器通过socket向Web服务器提交请求。HTTP的请求一般是GET或POST命令(POST用于FORM参数的传递)。GET命令的格式为:

GET 路径/文件名 HTTP/1.0

文件名指出所访问的文件,HTTP/1.0指出Web浏览器使用的HTTP版本。

应答:Web浏览器提交请求后,通过HTTP协议传送给Web服务器。Web服务器接到后,进行事务处理,处理结果又通过HTTP传回给Web浏览器,从而在Web浏览器上显示出所请求的页面。

例:假设客户机与www.mycomputer.com:8080/mydir/index.html建立了连接,就会发送GET命令:GET /mydir/index.html HTTP/1.0。主机名为www.mycomputer.com的Web服务器从它的文档空间中搜索子目录mydir的文件index.html。如果找到该文件,Web服务器把该文件内容传送给相应的Web浏览器。

为了告知 Web浏览器传送内容的类型,Web服务器首先传送一些HTTP头信息,然后传送具体内容(即HTTP体信息),HTTP头信息和HTTP体信息之间用一个空行分开。

常用的HTTP头信息有:

① HTTP 1.0 200 OK

这是Web服务器应答的第一行,列出服务器正在运行的HTTP版本号和应答代码。代码“200 OK”表示请求完成。

② MIME_Version:1.0

它指示MIME类型的版本。

③ content_type:类型

这个头信息非常重要,它指示HTTP体信息的MIME类型。如:content_type:text/html指示传送的数据是HTML文档。

④ content_length:长度值

它指示HTTP体信息的长度(字节)。

关闭连接:当应答结束后,Web浏览器与Web服务器必须断开,以保证其它Web浏览器能够与Web服务器建立连接。

二、C#实现Web服务器功能的程序设计

根据上述HTTP协议的作用原理,实现GET请求的Web服务器程序的方法如下:

创建TcpListener类对象,监听某端口(任意输入闲置端口 如:8080 )。

等待、接受客户机连接到该端口,得到与客户机连接的socket;

从与socket关联的输入流中读取一行客户机提交的请求信息,请求信息的格式为:GET 路径/文件名 HTTP/1.0

从请求信息中获取请求类型。如果请求类型是GET,则从请求信息中获取所访问的HTML文件名。没有HTML文件名时,则以index.html作为文件名;

如果HTML文件存在,则打开HTML文件,把HTTP头信息和HTML文件内容通过socket传回给Web浏览器,然后关闭文件。否则发送错误信息给Web浏览器;

关闭与相应Web浏览器连接的socket字。

实现的代码如下:
//webserver.cs//

namespace cnnbsun.webserver
{
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 = 8080 ; // 选者任何闲置端口

//开始兼听端口
//同时启动一个兼听进程
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("兼听端口时发生错误 :" +e.ToString());
}
}
public void SendHeader(string sHttpVersion, string sMIMEHeader, int iTotBytes, string sStatusCode, ref Socket mySocket)
{

String sBuffer = "";

if (sMIMEHeader.Length == 0 )
{
sMIMEHeader = "text/html"; // 默认 text/html
}

sBuffer = sBuffer + sHttpVersion + sStatusCode + "\r\n";
sBuffer = sBuffer + "Server: cx1193719-b\r\n";
sBuffer = sBuffer + "Content-Type: " + sMIMEHeader + "\r\n";
sBuffer = sBuffer + "Accept-Ranges: bytes\r\n";
sBuffer = sBuffer + "Content-Length: " + iTotBytes + "\r\n\r\n";

Byte[] bSendData = Encoding.ASCII.GetBytes(sBuffer);

SendToBrowser( bSendData, ref mySocket);

Console.WriteLine("Total Bytes : " + iTotBytes.ToString());

}

public void SendToBrowser(String sData, ref Socket mySocket)
{
SendToBrowser (Encoding.ASCII.GetBytes(sData), ref mySocket);
}

public void SendToBrowser(Byte[] bSendData, ref Socket mySocket)
{
int numBytes = 0;

try
{
if (mySocket.Connected)
{
if (( numBytes = mySocket.Send(bSendData, bSendData.Length,0)) == -1)
Console.WriteLine("Socket Error cannot Send Packet");
else
{
Console.WriteLine("No. of bytes send {0}" , numBytes);
}
}
else
Console.WriteLine("连接失败....");
}
catch (Exception e)
{
Console.WriteLine("发生错误 : {0} ", e );

}
}
public static void Main() 
{
MyWebServer MWS = new MyWebServer();
}
public void StartListen()
{

int iStartPos = 0;
String sRequest;
String sDirName;
String sRequestedFile;
String sErrorMessage;
String sLocalDir;
/注意设定你自己的虚拟目录/
String sMyWebServerRoot = "E:\\MyWebServerRoot\\"; //设置你的虚拟目录
//
String sPhysicalFilePath = "";
String sFormattedMessage = "";
String sResponse = "";

while(true)
{
//接受新连接
Socket mySocket = myListener.AcceptSocket() ;

Console.WriteLine ("Socket Type " +mySocket.SocketType ); 
if(mySocket.Connected)
{
Console.WriteLine("\nClient Connected!!\n==================\nCLient IP {0}\n",mySocket.RemoteEndPoint) ;

Byte[] bReceive = new Byte[1024] ;
int i = mySocket.Receive(bReceive,bReceive.Length,0) ;

//转换成字符串类型
string sBuffer = Encoding.ASCII.GetString(bReceive);

//只处理"get"请求类型
if (sBuffer.Substring(0,3) != "GET" )
{
Console.WriteLine("只处理get请求类型..");
mySocket.Close();
return;
}

// 查找 "HTTP" 的位置
iStartPos = sBuffer.IndexOf("HTTP",1);

string sHttpVersion = sBuffer.Substring(iStartPos,8);

// 得到请求类型和文件目录文件名
sRequest = sBuffer.Substring(0,iStartPos - 1);

sRequest.Replace("\\","/");

//如果结尾不是文件名也不是以"/"结尾则加"/"
if ((sRequest.IndexOf(".") <1) && (!sRequest.EndsWith("/")))
{
sRequest = sRequest + "/"; 
}

//得带请求文件名
iStartPos = sRequest.LastIndexOf("/") + 1;
sRequestedFile = sRequest.Substring(iStartPos);

//得到请求文件目录
sDirName = sRequest.Substring(sRequest.IndexOf("/"), sRequest.LastIndexOf("/")-3);

//获取虚拟目录物理路径
sLocalDir = sMyWebServerRoot;

Console.WriteLine("请求文件目录 : " + sLocalDir);

if (sLocalDir.Length == 0 )
{
sErrorMessage = "<H2>Error!! Requested Directory does not exists</H2><Br>";
SendHeader(sHttpVersion, "", sErrorMessage.Length, " 404 Not Found", ref mySocket);
SendToBrowser(sErrorMessage, ref mySocket);
mySocket.Close();
continue;
}

if (sRequestedFile.Length == 0 )
{
// 取得请求文件名
sRequestedFile = "index.html";
}

/
// 取得请求文件类型(设定为text/html)
/

String sMimeType = "text/html";

sPhysicalFilePath = sLocalDir + sRequestedFile;
Console.WriteLine("请求文件: " + sPhysicalFilePath);

if (File.Exists(sPhysicalFilePath) == false)
{

sErrorMessage = "<H2>404 Error! File Does Not Exists...</H2>";
SendHeader(sHttpVersion, "", sErrorMessage.Length, " 404 Not Found", ref mySocket);
SendToBrowser( sErrorMessage, ref mySocket);

Console.WriteLine(sFormattedMessage);
}

else
{
int iTotBytes=0;

sResponse ="";

FileStream fs = new FileStream(sPhysicalFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);

BinaryReader reader = new BinaryReader(fs);
byte[] bytes = new byte[fs.Length];
int read;
while((read = reader.Read(bytes, 0, bytes.Length)) != 0) 
{
sResponse = sResponse + Encoding.ASCII.GetString(bytes,0,read);

iTotBytes = iTotBytes + read;

}
reader.Close(); 
fs.Close();

SendHeader(sHttpVersion, sMimeType, iTotBytes, " 200 OK", ref mySocket);
SendToBrowser(bytes, ref mySocket);
//mySocket.Send(bytes, bytes.Length,0);

}
mySocket.Close(); 
}
}
}

}

}

///结束

将文件编译成EXE文件,就实现了简单的WEB服务器功能!
可以设定一个虚拟目录,进行测试!
asp.net提供承载asp.net的方法。详细可以看这个例子: http://www.asp.net/Projects/Cassini/Download/Default.aspx?tabindex=0&tabid=1 ;

转载于:https://www.cnblogs.com/cdo/archive/2005/12/08/293024.html

C#实现WEB服务器相关推荐

  1. Tengine Web服务器概述

    Tengine Web服务器概述 Tengine是由淘宝网发起的Web服务器项目.在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性.目的是打造一个高效.安全的Web平台. 发展 ...

  2. 2021年大数据ELK(二十二):采集Apache Web服务器日志

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 采集Apache Web服务器日志 一.需求 二.准备日志数据 三.使用Fil ...

  3. 最新的全球编程语言,操作系统,web服务器等使用率分析报告

    由www.w3techs.com 根据alexa排名前100万的网站数据给出的分析报告,并每天持续更新. 1.服务器端编程语言排名 http://w3techs.com/technologies/ov ...

  4. C语言实现的Web服务器

    另一篇: 标准C实现WEB服务器 http://blog.sina.com.cn/s/blog_4b73e7600100b02c.html 本文原文地址: http://blog.sina.com.c ...

  5. web服务器错误配置文件,web服务器http配置文件

    web服务器http配置文件 内容精选 换一换 通过调优Nginx的配置文件,可以有效的提高Nginx服务的性能.配置说明如表1所示.调优原则:以压满业务核为前提,用尽量少的中断核,配合配置网卡中断绑 ...

  6. lvs服务器需要开启web服务么_Nginx+Keepalived实现web服务器高可用

    1.Nginx 业务背景 现公司需求快速搭建web服务器,对外提供给用户web服务. 需求拆分 需要基于http协议的软件,搭建服务实现 介绍 常见用法: 1) web服务器软件 httpd http ...

  7. Web服务器 之 Apache 2.x 服务器中的URL重写的配置和应用

    作者:北南南北 来自:LinuxSir.Org 摘要: 本文是关于Apache 2.x 服务器中的URL别名规则的文档,它是通过rewrite模块来实现的.能过URL别名规则,我们能看到一个干净的UR ...

  8. 20步打造最安全的Nginx Web服务器

    Nginx是一个轻量级的,高性能的Web服务器以及反向代理和邮箱(IMAP/POP3)代理服务器.它运行在UNIX,GNU/Linux,BSD各种版本,Mac OS X,Solaris和Windows ...

  9. Forefront_TMG_2010-TMG发布Web服务器

    1.环境拓扑图: 2.准备DMZ区域的Web服务器: 安装Web服务器: 在DMZ区域的Web服务器进行测试: 3.TMG发布Web服务器: 打开TMG管理控制台,新建"网站发布规则&quo ...

  10. 如何保护Ubuntu 16.04上的NGINX Web服务器

    什么是 Let's Encrypt Let's Encrypt 是互联网安全研究组织 (ISRG) 提供的免费证书认证机构.它提供了一种轻松自动的方式来获取免费的 SSL/TLS 证书 - 这是在 W ...

最新文章

  1. 解决iOS设备屏幕切换时页面造成的问题
  2. linux find查找文件然后删除,linu查找find命令及删除7天前的文件
  3. 快速检查REST API是否有效的方法-从清单文件中获取详细信息
  4. crontab下执行设置壁纸出错问题
  5. tl494cn逆变器电路图_TL494逆变器电路图(400W)
  6. PAT甲级1017 (模拟排序)
  7. 盈不足术与老鼠打洞问题的近似解
  8. Win32汇编——动态链接库
  9. 资源 | 忘了Python关键语句?这份备忘录拯救你的记忆
  10. 为何高端FPGA都非常重视软件
  11. 关于linux系统安装zabbix报错的解决方案
  12. 【PC工具】可能是最好用的下载工具:IDM特点及功能汇总,IDM破解版下载,PC好用的迅雷下载版本合集...
  13. 艺术类职称计算机考试,2017年职称计算机考试Word2003巩固练习题20
  14. 没有人会疼自己没人会懂,会理解:伤感空间日志
  15. 各种 PNG图片压缩对比分析
  16. Python大数据+人工智能 学科视频教程
  17. 纽约州立大学水牛城分校计算机科学专业,纽约州立大学水牛城分校会不会不容易毕业?...
  18. ANDROID 11 文件系统挂载
  19. centos 解除链接_KeyShot 9.2 新功能介绍!(附下载链接)
  20. 12_JavaScript数据结构与算法(十二)二叉树

热门文章

  1. python 表格格式输出_Python笔记---DAY3:格式化输出、for循环、列表操作
  2. 霍夫直线检测python_python+opencv实现霍夫变换检测直线
  3. 一拍是多少秒 计算机制音乐,E哥谈如何计算音乐的拍数及每拍时值是多少及数学好对学音乐有帮助吗?...
  4. ElasticSearch概述及安装
  5. java 判断值是否设置,获取Java中“-非法访问”设置的当前值
  6. oracle是delete可以加并行吗,提高Oracle DELETE性能的策略
  7. STM32板子电源绘制原理
  8. 素数筛选法(埃氏筛 欧拉筛)
  9. python 文件操作不被打断_python学习六文件操作和异常处理
  10. php去掉关联数组,大家都应该掌握的PHP关联数组使用技巧