(转)C#自制Web 服务器开发:用C#开发自己的Web服务器

当输入:127.0.0.1:5050 GET / HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: 127.0.0.1:5050
DNT: 1
Connection: Keep-Alive
Cookie: s_pers=%20s_fid%3D5E4387B367FCC613-0DC7FD9C6D76C087%7C1453856077838%3B%20s_vs%3D1%7C1390785877860%3B%20s_nr%3D1390784077867-New%7C1422320077867%3B http://127.0.0.1:5050/index.html GET /index.html HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: 127.0.0.1:5050
DNT: 1
Connection: Keep-Alive
Cookie: s_pers=%20s_fid%3D5E4387B367FCC613-0DC7FD9C6D76C087%7C1453856077838%3B%20s_vs%3D1%7C1390785877860%3B%20s_nr%3D1390784077867-New%7C1422320077867%3B 提交表单 POST / HTTP/1.1
Host: 127.0.0.1:5050
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:27.0) Gecko/20100101 Firefox/27.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Cookie: s_pers=%20s_fid%3D5E4387B367FCC613-0DC7FD9C6D76C087%7C1453856077838%3B%20s_vs%3D1%7C1390785877860%3B%20s_nr%3D1390784077867-New%7C1422320077867%3B
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 51 txtName=&txtClass=&txtPassword=&Submit=%CC%E1%BD%BB 提交表单 2 POST /CCC.asp HTTP/1.1
Host: 127.0.0.1:5050
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:27.0) Gecko/20100101 Firefox/27.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Cookie: s_pers=%20s_fid%3D5E4387B367FCC613-0DC7FD9C6D76C087%7C1453856077838%3B%20s_vs%3D1%7C1390785877860%3B%20s_nr%3D1390784077867-New%7C1422320077867%3B
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 68 txtName=name&txtClass=class&txtPassword=password&Submit=%CC%E1%BD%BB 提交表单3
POST /CCC.asp HTTP/1.1
Host: 127.0.0.1:5050
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:27.0) Gecko/20100101 Firefox/27.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Cookie: s_pers=%20s_fid%3D5E4387B367FCC613-0DC7FD9C6D76C087%7C1453856077838%3B%20s_vs%3D1%7C1390785877860%3B%20s_nr%3D1390784077867-New%7C1422320077867%3B
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 93 txtName=%D5%C5%C8%FD&txtClass=%B8%DF%D2%BB%B6%FE%B0%E0&txtPassword=990749&Submit=%CC%E1%BD%BB

以上是 浏览器在浏览时发送给服务器的数据内容.在不同情况下会有所不同.不过,一般数据量都很小.
以上的 %D5%C5%C8%FD 实际上是 urlencode 编码方式:在程序开发的过程,需要对其进行解码
由于IIS的不稳定性和难实施性(对操作系统太挑剔),一直想做个自己的轻量级Web服务器。
今天终于抽出时间,借助网络上的实例,实现了自己的服务器,计划以后在项目开发时尝试取代IIS服务器。
在此把整体实现过程记录下,以备后用。
技术实现原理:
1.需要了解HTTP的工作原理
2.需要了解基于C#的SOCKET编程,TcpListener类对象,监听端口
一、启动VS2005,新建一个控制台程序,命名:ConsoleApplication1
二、在添加CS文件,使名:MyWebServer.cs
三、实现类MyWebServer,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading; namespace WindowsFormsApplication1
{
class MyWebServer
{
private TcpListener myListener;
private int port = 8899; // 选者任何闲置端口
//开始兼听端口
//同时启动一个兼听进程
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 void StartListen()
{ int iStartPos = 0;
String sRequest;
String sDirName;
String sRequestedFile;
String sErrorMessage;
String sLocalDir;
/////////////////////////////////////注意设定你自己的虚拟目录/////////////////////////////////////
String sMyWebServerRoot = "C:\\Cassini\"; //设置你的虚拟目录
//////////////////////////
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"; string sPhysicalFilePath = sLocalDir + sRequestedFile;
Console.WriteLine("请求文件: " + sPhysicalFilePath); if (File.Exists(sPhysicalFilePath) == false)
{ sErrorMessage = "<script language='javascript'>alert('你好呀,我不是IIS服务器!');</script>";
//SendHeader(sHttpVersion, "", sErrorMessage.Length, " 404 Not Found", ref mySocket);
//SendToBrowser(sErrorMessage, ref mySocket);
byte[] bytes = Encoding.GetEncoding("GB2312").GetBytes(sErrorMessage);
SendHeader(sHttpVersion, sMimeType, bytes.Length, " 200 OK", ref mySocket);
SendToBrowser(bytes, 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();
}
}
}
}
}

四、编辑Program.cs,启动监听

static void Main(string[] args)
{
MyWebServer MWS = new MyWebServer();
Console.Read();
}

(转)C#自制Web 服务器开发:用C#开发自己的Web服务器的更多相关文章
- 了不起的Node.js: 将JavaScript进行到底(Web开发首选,实时,跨多服务器,高并发)
了不起的Node.js: 将JavaScript进行到底(Web开发首选,实时,跨多服务器,高并发) Guillermo Rauch 编 赵静 译 ISBN 978-7-121-21769-2 2 ...
- WEB开发:如何用js来模拟服务器的ajax响应,不依赖服务器来编写前端代码
一.问题的提出 目前web前端开发,主流的思路是: 1)编写静态的html文件(不使用模板技术,与服务器无关) 2)页面通过ajax与服务器交互,进行数据的传输,数据格式为json格式 这里存在一个问 ...
- IIS服务器 远程发布(Web Deploy)配置 VS2010 开发环境 Windows Server 2008服务器系统
原文:IIS服务器 远程发布(Web Deploy)配置 VS2010 开发环境 Windows Server 2008服务器系统 asp.net 网站有三种常用的发布方式:分别是拷贝开发机上发布好的 ...
- “GIS DICTIONARY A-Z” 查询页面开发(3)—— 基础知识之服务器、IP地址、域名、DNS、端口以及Web程序的访问流程
今天补一补基础知识: 一.服务器:能够提供服务的机器,取决于机器上安装的软件(服务软件).服务器响应服务请求,并进行处理. Web服务器:提供Web服务,即网站访问.常见Web服务软件:Apache( ...
- java web学习总结(六) -------------------servlet开发(二)
一.ServletConfig讲解 1.1.配置Servlet初始化参数 在Servlet的配置文件web.xml中,可以使用一个或多个<init-param>标签为servlet配置一些 ...
- SNF开发平台WinForm之十三-单独从服务器上获取PDF文件进行显示-SNF快速开发平台3.3-Spring.Net.Framework
1运行效果: 2开发实现: 如果需要单独显示PDF文件时用下面代码去实现,指定url地址. 地址: . 获取附件管理的实体对象: List<KeyValuePair<string, obj ...
- Web程序员开发App系列 - 开发我的第一个App,源码下载
Web程序员开发App系列 Web程序员开发App系列 - 认识HBuilder Web程序员开发App系列 - 申请苹果开发者账号 Web程序员开发App系列 - 调试Android和iOS手机代码 ...
- java web 学习六(servlet开发2)
一.ServletConfig讲解 1.1.配置Servlet初始化参数 在Servlet的配置文件web.xml中,可以使用一个或多个<init-param>标签为servlet配置一些 ...
- Apache Solr采用Java开发、基于Lucene的全文搜索服务器
http://docs.spring.io/spring-data/solr/ 首先介绍一下solr: Apache Solr (读音: SOLer) 是一个开源.高性能.采用Java开发.基于Luc ...
- 触摸屏网站开发系列(一)-ios web App应用程序(ios meta)
触摸屏网站的开发其实现在来讲比前几年移动端网站开发好多了,触摸屏设备IOS.Android.BBOS6等系统自带浏览器均为WEBKIT核心,这就说明PC上面尚未立行的HTML5 CSS3能够运用在这里 ...
随机推荐
- 02.Elasticsearch入门
Elasticsearch支持Http类型的Restful风格API请求,需要打开9200端口.Elasticsearch服务会监听两个端口9200和9300,9200提供Http Restf ...
- Maven 构建Spring-Boot工程报错
Execution default of goal org.springframework.boot:spring-boot-maven-plugin:1.5.6.RELEASE:repackage ...
- 启动phpstyle Apache的80端口被win7的System PID=4的进程占用的解决方法 以及 如何在phpStyle里发布程序
学习前端是,用到Ajax,php语言,操作mysql数据库,浏览器无法解析php代码(把源码输出):原因,我之前用的是tomcat服务器写jsp,servlet,php用的是apache服务器,没有配 ...
- Python全栈day10(运算符)
一,运算符 + - * . ** % // 二,in 和not in 一个字符串包含多个字符可以通过in判断字符是否属于改字符串 >>> name = "zhangsan& ...
- jstree的checkbox实例+详解
jstree的checkbox实例较少,思索后决定进行一下整理,先上代码 $("#filtrate_row").on("loaded.jstree",funct ...
- linux使用http代理连接服务器设置方法
连接腾讯的额cvm服务器官方给出的也有个方法,详细可以看这里:http://wiki.open.qq.com/wiki/%E4%BB%8E%E6%9C%AC%E5%9C%B0linux%E6%9C%B ...
- Linux NAPI处理流程分析
2017-05-10 今天重点对linux网络数据包的处理做下分析,但是并不关系到上层协议,仅仅到链路层. 之前转载过一篇文章,对NAPI做了比较详尽的分析,本文结合Linux内核源代码,对当前网络数 ...
- Unity3D优化技巧系列七
笔者介绍:姜雪伟,IT公司技术合伙人.IT高级讲师,CSDN社区专家,特邀编辑.畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D ...
- 安卓android的联系人的contacts, raw contacts, and data的区别
https://stackoverflow.com/questions/5151885/android-new-data-record-is-added-to-the-wrong-contact/51 ...
- POJ1269:Intersecting Lines(判断两条直线的关系)
题目:POJ1269 题意:给你两条直线的坐标,判断两条直线是否共线.平行.相交,若相交,求出交点. 思路:直线相交判断.如果相交求交点. 首先先判断是否共线,之后判断是否平行,如果都不是就直接求交点 ...