本文基于.net core 的控制台程序作为服务端

main函数:

 class Program
{
static void Main(string[] args)
{
Console.WriteLine("The server is starting......"); new Server().StartServer(); Console.ReadLine();
}
}

其中核心代码在Server这个类上面:

 public class Server
{
private Socket socketWatch = null;
private Thread threadWatch = null;
private string ipAddress = "127.0.0.1";
private string port = ""; public Server()
{
socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socketWatch.Bind(new IPEndPoint(IPAddress.Parse(ipAddress), int.Parse(port)));
socketWatch.Listen();
// 创建Thread->后台执行
threadWatch = new Thread(ListenClientConnect);
threadWatch.IsBackground = true;
} public void StartServer()
{
threadWatch.Start(socketWatch);
} private void ListenClientConnect(object objSocket)
{
Socket socketListen = objSocket as Socket; while (true)
{
Socket proxSocket = socketListen.Accept();
byte[] data = new byte[ * * ];
int length = proxSocket.Receive(data, , data.Length, SocketFlags.None);
// Step1:接收HTTP请求
string requestText = Encoding.Default.GetString(data, , length);
HttpContext context = new HttpContext(requestText);
// Step2:处理HTTP请求
HttpApplication application = new HttpApplication();
application.ProcessRequest(context);
// Step3:响应HTTP请求
Console.WriteLine(string.Format("{0} {1} from {2}", context.Request.HttpMethod, context.Request.Url, proxSocket.RemoteEndPoint.ToString()));
proxSocket.Send(context.Response.GetResponseHeader());
proxSocket.Send(context.Response.Body);
// Step4:即时关闭Socket连接
proxSocket.Shutdown(SocketShutdown.Both);
proxSocket.Close();
}
}
}

上面代码中,主要是基于Socket和线程。在构造函数中初始化了服务器端Socket,还初始化了Thread,并且设置为后台线程。ListenClientConnect函数主要做的事情是接受浏览器请求,并且转化为HttpContext和HttpApplication,最后输出响应并且关闭socket。

这里面有几个比较重要的类,主要如下:

 public class HttpContext
{
public HttpRequest Request { get; set; }
public HttpResponse Response { get; set; } public HttpContext(string requestText)
{
Request = new HttpRequest(requestText);
Response = new HttpResponse();
}
}

HttpContext模拟asp的HttpContext,里面有两个看起来很熟悉的类,HttpRequest和HttpResponse

 public class HttpRequest
{
public HttpRequest(string requestText)
{
string[] lines = requestText.Replace("\r\n", "\r").Split('\r');
string[] requestLines = lines[].Split(' ');
// 获取HTTP请求方式、请求的URL地址、HTTP协议版本
if(requestLines.Length >= )
{
HttpMethod = requestLines[];
Url = requestLines[];
HttpVersion = requestLines[];
}
}
// 请求方式:GET or POST?
public string HttpMethod { get; set; }
// 请求URL
public string Url { get; set; }
// Http协议版本
public string HttpVersion { get; set; }
// 请求头
public Dictionary<string, string> HeaderDictionary { get; set; }
// 请求体
public Dictionary<string, string> BodyDictionary { get; set; }
}
 public class HttpResponse
{
// 响应状态码
public string StateCode { get; set; }
// 响应状态描述
public string StateDescription { get; set; }
// 响应内容类型
public string ContentType { get; set; }
//响应报文的正文内容
public byte[] Body { get; set; } // 生成响应头信息
public byte[] GetResponseHeader()
{
string strRequestHeader = string.Format(@"HTTP/1.1 {0} {1}
Content-Type: {2}
Accept-Ranges: bytes
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: {3}
Content-Length: {4} ", StateCode, StateDescription, ContentType, string.Format("{0:R}", DateTime.Now), Body.Length); return Encoding.UTF8.GetBytes(strRequestHeader);
}
}

这两个核心类是关于请求和响应的。

IHttpHandler是另外一个很熟悉的接口,一般处理程序中都会实例化它

 public interface IHttpHandler
{
void ProcessRequest(HttpContext context);
}

我们处理请求的时候就是依靠实例化这个接口了,在我们的实例上面就是HttpApplication

 public class HttpApplication : IHttpHandler
{
// 对请求上下文进行处理
public void ProcessRequest(HttpContext context)
{
// 1.获取网站根路径
if(string.IsNullOrEmpty(context.Request.Url))
{
return;
}
string bastPath = AppDomain.CurrentDomain.BaseDirectory;
string fileName = Path.Combine(bastPath, "LZZWebSite", context.Request.Url.TrimStart('/'));
string fileExtension = Path.GetExtension(context.Request.Url);
// 2.处理动态文件请求
if (fileExtension.Equals(".aspx") || fileExtension.Equals(".ashx"))
{
string className = Path.GetFileNameWithoutExtension(context.Request.Url);
IHttpHandler handler = Assembly.GetExecutingAssembly().CreateInstance($"lzzWebServerDemo.Page.{className}", true) as IHttpHandler;
handler.ProcessRequest(context);
return;
}
// 3.处理静态文件请求
if (!File.Exists(fileName))
{
context.Response.StateCode = "";
context.Response.StateDescription = "Not Found";
context.Response.ContentType = "text/html";
string notExistHtml = Path.Combine(bastPath, @"LZZWebSite\notfound.html");
context.Response.Body = File.ReadAllBytes(notExistHtml);
}
else
{
context.Response.StateCode = "";
context.Response.StateDescription = "OK";
context.Response.ContentType = GetContenType(Path.GetExtension(context.Request.Url));
context.Response.Body = File.ReadAllBytes(fileName);
}
} // 根据文件扩展名获取内容类型
public string GetContenType(string fileExtension)
{
string type = "text/html; charset=UTF-8";
switch (fileExtension)
{
case ".aspx":
case ".html":
case ".htm":
type = "text/html; charset=UTF-8";
break;
case ".png":
type = "image/png";
break;
case ".gif":
type = "image/gif";
break;
case ".jpg":
case ".jpeg":
type = "image/jpeg";
break;
case ".css":
type = "text/css";
break;
case ".js":
type = "application/x-javascript";
break;
default:
type = "text/plain; charset=gbk";
break;
}
return type;
}

上面的业务比较清晰,如果是静态资源,就直接响应返回。如果是动态资源,例如aspx、ashx的话就通过反射实例化对应的处理类。我们例子上是这样模拟的:

 public class LzzPage: IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
StringBuilder sbText = new StringBuilder();
sbText.Append("<html>");
sbText.Append("<head></head>");
sbText.Append("<body>");
sbText.Append("<h1>demo</h1>");
sbText.Append("lzzdemolzzdemo");
sbText.Append(string.Format("<h3>time:{0}</h3>", DateTime.Now.ToString()));
sbText.Append("</body>");
sbText.Append("</html>");
context.Response.Body = Encoding.UTF8.GetBytes(sbText.ToString());
context.Response.StateCode = "";
context.Response.ContentType = "text/html";
context.Response.StateDescription = "OK";
}
}

最后来一张整个体统的结构图

运行图:

开发属于自己的Web服务器的更多相关文章

  1. 自己动手模拟开发一个简单的Web服务器

    开篇:每当我们将开发好的ASP.NET网站部署到IIS服务器中,在浏览器正常浏览页面时,可曾想过Web服务器是怎么工作的,其原理是什么?“纸上得来终觉浅,绝知此事要躬行”,于是我们自己模拟一个简单的W ...

  2. Java开发环境配置(5)--Web 服务器--Tomcat--安装过程遇到的问题

    1.参考例子:--- 怎样安装配置tomcat 8_百度经验https://jingyan.baidu.com/article/ff42efa91132a0c19e220208.html 安装与配置T ...

  3. 【安富莱专题教程第3期】开发板搭建Web服务器,利用花生壳让电脑和手机可以外网远程监控

    说明:1.  开发板Web服务器的设计可以看我们之前发布的史诗级网络教程:链接.2.  需要复杂些的Web设计模板,可以使用我们V6开发板发布的综合Demo:链接.3.  教程中使用的是花生壳免费版, ...

  4. [思路]为什么要做一个Web服务器

    对于.net开发者而言,提到Web服务器最容易想到的就是IIS了. IIS功能强大,配置繁多,但不免对普通用户而言过于复杂,另外在云时代的今天,同时维护多个IIS或远程维护IIS还是有诸多不便的,有很 ...

  5. 04-HTTP协议和静态Web服务器

    一.HTTP协议(HyperText Transfer Protocol)     超文本传输协议,超文本是超级文本的缩写,是指超越文本限制或者超链接,比如:图片.音乐.视频.超链接等等都属于超文本. ...

  6. 嵌入式web服务器BOA的移植及应用

    嵌入式web服务器子系统 一.嵌入式web服务器的控制流程 如下图所示,嵌入式web服务器可实现通过网络远程控制嵌入式开发板,便捷实用. 控制流程:浏览器 --->>>嵌入式开发板 ...

  7. Nginx 外的另一选择,轻量级开源 Web 服务器 Tengine 发布新版本

    新版发布 近日,轻量级开源 Web 服务器 Tengine 发布了2.3.0版本,新增如下特性: ngx_http_proxy_connect_module,该模块让 Tengine 可以用于正向代理 ...

  8. ASP.NET 开发必备知识点(1):如何让Asp.net网站运行在自定义的Web服务器上

    一.前言 大家都知道,在之前,我们Asp.net 的网站都只能部署在IIS上,并且IIS也只存在于Windows上,这样Asp.net开发的网站就难以做到跨平台.由于微软的各项技术的开源,所以微软自然 ...

  9. Web服务器具体开发流程

    下面是我个人对Web服务器开发流程的一点理解,下面做出了大概的模型,实现了基本的功能,下面也有所有的代码可以提供参考: 一开始学的时候不要把网站想的太复杂了,把网站的流程和大概的原理框架搞清楚,在通过 ...

随机推荐

  1. new Image().src资源重复请求问题

    const img = new Image(); img.setAttribute("crossOrigin", 'Anonymous'); img.src = url + '?t ...

  2. Buffer.h

    #ifndef __NOXIMBUFFER_H__ #define __NOXIMBUFFER_H__ #include <cassert> #include <queue> ...

  3. abaqus修改inp直接建立工程

    前面已经知道,通过修改以下inp的节点和单元编号,就可以新建模型,可是对于大的工程来说,逐个选取单元进行添加材料以及确定哪步进行填土仍是比较麻烦的(如果工程网格划分好并告知哪些单元好属于哪些材料,哪些 ...

  4. 欣赏<沉默的大多数>——王小波

    君特·格拉斯在<铁皮鼓>里,写了一个不肯长大的人.小奥斯卡发现周围的世界太过荒诞,就暗下决心要永远做小孩子.在冥冥之中,有一种力量成全了他的决心,所以他就成了个侏儒.这个故事太过神奇,但很 ...

  5. Paper | 深度网络中特征的可迁移性

    目录 1. 核心贡献 2. 实验设置 2.1. 任务设置 2.2. 网络设置 3. 实验结果 4. 启发 论文:How transferable are features in deep neural ...

  6. 关于数据库连接时URL的问题

    最近在写一个简单的增删改查的代码时,遇到保存的中文都会变成问号(?),由于刚开始只是一些数据的保存,所以认为之后只要对数据库的编码进行修改即可,但是后来要对数据进行查找的时候发现根本查找不到, 当时用 ...

  7. GitHub和Git(待补充)

    仓库(Repository):存放项目代码,每个项目对应一个仓库. 收藏(Star) 复制(Fork):克隆并生成新的仓库,from某某.以此为基础修改或应用项目.pull request,源仓库会查 ...

  8. ADC_DMA_TIM

    /************************************************************************** * 文件名:ADC.h * * 编写人:离逝的风 ...

  9. noip第26课资料

  10. Maven和Gradle的区别

    转自:http://www.infoq.com/cn/news/2011/04/xxb-maven-6-gradle Maven面临的挑战 软件行业新旧交替的速度之快往往令人咂舌,不用多少时间,你就会 ...