一步步搭建自己的web服务器
IIS或者其他Web服务器究竟做了哪些工作,让浏览器请求一个URL地址后显示一个漂亮的网页?要想弄清这个疑问,我想我们可以自己写一个简单的web服务器。
思路:
- 创建socket监听浏览器请求。
- 连接成功,接受浏览器的请求数据。
- 响应浏览器的请求。(我们只响应静态文件) 。
好的,思路很清晰。下面就跟着我动手一步步用代码实现。
1、创建socket监听浏览器请求。
当浏览器请求域名,DNS将域名解析为IP地址。带着缺省的端口80访问我们的服务器。所以Socket的监听,也需要绑定IP和端口。
代码:
- // 窗体加载
- private void Form1_Load(object sender, EventArgs e)
- {
- // 关闭线程操作检测
- Control.CheckForIllegalCrossThreadCalls = false;
- Log("服务器启动中 >>>");
- IPAddress ip = IPAddress.Parse(txtIP.Text);
- IPEndPoint p = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
- socketWatch.Bind(p);
- socketWatch.Listen();
- // 为了不阻塞主线程,开启后台线程,监听浏览器请求。
- Thread t = new Thread(Listen);
- t.IsBackground = true;
- t.Start();
- Log("服务器启动成功。");
- }
Listen 进程只需要无限循环接受浏览器发送过来的请求。
private void Listen()
{
while (true)
{
Socket sender=socketWatch.Accept();
Log(sender.RemoteEndPoint.ToString() + "连接成功");
}
}
辅助方法,显示提示信息。(不重要)
- // 显示提示信息
- private void Log(string msg)
- {
- txtMsg.AppendText(msg + "\r\n");
- }
执行结果
打开我们的winform程序。
打开浏览器访问: http://192.168.95.1:3099/ 地址
就能看到以下结果:
2、连接成功,接受浏览器的请求数据。
分析:
浏览器的请求到达服务器后,我们要接待他,就要问他是过来干嘛的。
要和浏览器交流,那么服务器和浏览器就应该说一种语言。这个语言就是http协议。
(对HTTP协议还不太了解的园友可以参考:http协议知识整理)
根据HTTP协议,浏览器请求服务器的格式都是规定好的,
所以我们只需要根据格式进行拆分,获取我们感兴趣的数据。
这件事情,已经不属于form1.cs这个类的能力范围了。所以我们找一个管家HttpManager来帮我们处理。至于怎么处理form1不用管,他只需要告诉管家就可以了。
代码:
在form1.cs的Listen中创建管家
- HttpManager manager = new HttpManager(sender, Log);
管家接收基础的数据后,再交给专门处理请求数据的对象HttpRequest。
- class HttpManager
- {
- private Socket socket;
- private Action<string> Log;
- public HttpManager(Socket socket, Action<string> act)
- {
- this.socket = socket;
- this.Log = act;
- // 接收消息
- string msg = ReceiveMsg();
- Log(msg);
- try
- {
- // 去找请求对象,拿到我们需要的数据。
- HttpRequest request = new HttpRequest(msg);
- }
- catch (Exception ex)
- {
- Log(ex.Message);
- }
- }
- // 接受浏览器请求报文
- private string ReceiveMsg()
- {
- byte[] date = new byte[ * ];
- int count = socket.Receive(date);
- return Encoding.UTF8.GetString(date, , count);
- }
- }
核心的HttpResponse:
- class HttpRequest
- {
- // 请求原始地址 /xxx/xxx.xxxx
- public string RawUrl { get; set; }
- // 请求类型 Post/Get
- public string Method;
- public HttpRequest(string msg)
- {
- string[] lines = msg.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
- string[] arrays = lines[].Split(' ');
- Method = arrays[];
- RawUrl = arrays[];
- }
- }
3、响应浏览器的请求。
响应过程其实也非常简单,IO读取浏览器需要请求的数据,拼接响应报文返回给浏览器。
在HttpManager类接收完数据后,调用响应对象。来帮我们处理响应。
- // 构造响应报文,响应请求。
- HttpResponse response = new HttpResponse(request.RawUrl, socket, Log);
核心HttpResponse代码
- class HttpResponse
- {
- public int StatusCode { get; set; }
- public Dictionary<int, string> Dic = new Dictionary<int, string>();
- public string ContentType { get; set; }
- public int ContentLength { get; set; }
- public byte[] Data { get; set; }
- public Socket Socket { get; set; }
- public Action<string> Log { get; set; }
- public HttpResponse(string rawUrl, Socket socket, Action<string> log)
- {
- this.Socket = socket;
- FillDic();
- this.Log = log;
- // 判断是否为静态资源
- if (Judge(rawUrl))
- {
- // IO 读取资源
- Data = ReadFile(rawUrl);
- if (Data == null)
- {
- // 404 没有这个文件
- StatusCode = ;
- string msg = "没有找到这个文件。";
- ContentType = "text/html";
- Data = Encoding.Default.GetBytes(msg);
- ContentLength = Data.Length;
- ContentType = "text/html";
- SendData();
- }
- else
- {
- ContentLength = Data.Length;
- StatusCode = ;
- ContentType = GetContentType(rawUrl);
- // 响应请求
- SendData();
- }
- }
- else
- {
- // 不处理
- string msg = "只处理静态文件。";
- Data = Encoding.Default.GetBytes(msg);
- ContentLength = Data.Length;
- StatusCode = ;
- ContentType = "text/html";
- // 响应请求
- SendData();
- }
- }
- // 判断文件是否为静态资源
- private bool Judge(string rawUrl)
- {
- bool isStatic = false;
- string ext = Path.GetExtension(rawUrl);
- switch (ext)
- {
- case ".html":
- case ".htm":
- case ".jpg":
- case ".png":
- case ".gif":
- case ".js":
- case ".css":
- case ".ico": isStatic = true; break;
- }
- return isStatic;
- }
- // 响应
- private void SendData()
- {
- StringBuilder sb = new System.Text.StringBuilder();
- sb.Append("HTTP/1.1 " + StatusCode + " " + Dic[StatusCode] + "\r\n");
- sb.Append("Server: ksn/1.0\r\n");
- sb.Append("Content-Type: " + ContentType + "\r\n");
- sb.Append("Content-Length: " + ContentLength + "\r\n");
- sb.Append("\r\n");
- Log("响应报文: \r\n" + sb.ToString());
- byte[] head = Encoding.UTF8.GetBytes(sb.ToString());
- List<byte> res = new List<byte>();
- res.AddRange(head);
- if (this.Data != null)
- {
- res.AddRange(this.Data);
- }
- Socket.Send(res.ToArray());
- }
- private string GetContentType(string rawUrl)
- {
- string ct = "text/html";
- string ext = Path.GetExtension(rawUrl);
- switch (ext)
- {
- case ".js": ct = "text/javascript";
- break;
- case ".css": ct = "text/css";
- break;
- case ".jpg": ct = "image/jpeg";
- break;
- case ".png": ct = "image/png";
- break;
- case ".gif": ct = "image/gif";
- break;
- case ".ico": ct = "image/x-ico";
- break;
- }
- return ct;
- }
- // 初始化状态码
- private void FillDic()
- {
- Dic.Add(, "Ok");
- Dic.Add(, "Not Found");
- Dic.Add(, "Internal Error");
- }
- // 读取请求的资源
- private byte[] ReadFile(string rawUrl)
- {
- string path = AppDomain.CurrentDomain.BaseDirectory;
- path = path + "web" + rawUrl;
- if (File.Exists(path))
- {
- using (FileStream fs = new FileStream(path, FileMode.Open))
- {
- byte[] data = new byte[fs.Length];
- fs.Read(data, , data.Length);
- return data;
- }
- }
- else
- {
- return null;
- }
- }
- }
这个类的代码比较多,但是不难,都是按照顺序一步步往下走的。其实web服务器大致就做了这些事情。只不过封装的东西更多,功能更完善。
资源:
一步步搭建自己的web服务器的更多相关文章
- linux系统下搭建自己的web服务器
之前在windows 2008 server上搭建了一个用于测试的web服务器,但是在打开网站的时候特别的慢,尤其是图片的加载都会失败,当时以为是路径的问题,但是在服务器上自己打开都特别慢,自己实在找 ...
- [阿里云部署] Ubuntu+Flask+Nginx+uWSGI+Mysql搭建阿里云Web服务器
部署地址:123.56.7.181 Ubuntu+Flask+Nginx+uWSGI+Mysql搭建阿里云Web服务器 这个标题就比之前的"ECS服务器配置Web环境的全过程及参考资料&qu ...
- 基于python2【重要】怎么自行搭建简单的web服务器
基本流程:1.需要的支持 1)python本身有SimpleHTTPServer 2)ForkStaticServer.py支持,该文件放在python7目录下 3)将希望共享 ...
- nginx搭建前端项目web服务器以及利用反向代理调试远程后台接口
前端同学用nginx搭建自己的web服务器,后台程序专门部署在一台服务器上(我们之前公司就有三套环境,开发/测试/生产),这样做的好处是 1.前端代码基本都是静态文件,重启一次很快,也就几秒钟时间. ...
- 使用 Nginx 搭建静态资源 web 服务器
在搭建网站的时候,往往会加载很多的图片,如果都从 Tomcat 服务器来获取静态资源,这样会增加服务器的负载,使得服务器运行 速度非常慢,这时可以使用 Nginx 服务器来加载这些静态资源,这样就可以 ...
- 用go-module作为包管理器搭建go的web服务器
本篇博客主要介绍了如何从零开始,使用Go Module作为依赖管理,基于Gin来一步一步搭建Go的Web服务器.并使用Endless来使服务器平滑重启,使用Swagger来自动生成Api文档. 源码在 ...
- 使用 Nodejs 搭建简单的Web服务器
使用Nodejs搭建Web服务器是学习Node.js比较全面的入门教程,因为要完成一个简单的Web服务器,你需要学习Nodejs中几个比较重要的模块,比如:http协议模块.文件系统.url解析模块. ...
- qingshow “不积跬步无以至千里,不积小流无以成江海”。--荀子《劝学篇》 用tomcat+花生壳搭建自己的web服务器+域名(参考)
链接地址:http://www.blogjava.net/qingshow/archive/2010/01/17/309846.html 用tomcat搭建web服务器 目标:免费拥有自己的网站及域名 ...
- 【小姿势】如何搭建ipa下载web服务器(直接在手机打开浏览器安装)
前提: 1) 有个一个现成的web服务器,我用是nodejs. 2) 有个能在用你手机安装的ipa 3) 有个github账号 开搞: 1.用http://plist.iosdev.top/plist ...
随机推荐
- Servlet3.0异步请求
在Servlet3.0之前,Servlet采用Thread-Per-Request的方式处理请求 即每次Http请求都有一个线程从头到尾负责处理 如果一个请求需要进行IO操作,比如访问数据库.调用第三 ...
- Axis.Labels.CustomSize
tChart1.Axes.Bottom.Labels.CustomSize = ; //Changes spacing occupied by the axis labels between the ...
- window_onload和body_onload
onload 事件 Event 对象 定义和用法 onload 事件会在页面或图像加载完成后立即发生. 语法 onload="SomeJavaScriptCode" 参数 描述 S ...
- matplotlib 初步学习
author:pprp Matplotlib数据可视化 [TOC] 安装 conda install matplotlib sudo apt-get install python-matplotlib ...
- vc 导出函数/调用
loader(exe): #include "stdafx.h" #include <Windows.h> #include <stdio.h> #defi ...
- 从Github上轻松安装R包—githubinstall包--转载
1.综述 越来越多的R包正在由世界上不同的人所创建,其中一部分原因是devtools包使得开发R包1变得更加简单.devtools包不仅让开发R包变得简单,而且用于分发R包. 当开发者发布一个R包的时 ...
- Android显示框架:自定义View实践之绘制篇
文章目录 一 View 二 Paint 2.1 颜色处理 2.2 文字处理 2.3 特殊处理 三 Canvas 3.1 界面绘制 3.2 范围裁切 3.3 集合变换 四 Path 4.1 添加图形 4 ...
- Unity使用Win10语音
1. 引入头文件 using UnityEngine.Windows.Speech; 2. 设置识别词 public string[] keywords = new string[] { ...
- 如何成为 Python 高手
这篇文章主要是对我收集的一些文章的摘要.因为已经有很多比我有才华的人写出了大量关于如何成为优秀Python程序员的好文章. 我的总结主要集中在四个基本题目上:函数式编程,性能,测试,编码规范.如果一个 ...
- UVALive - 6709树套树
题意:给你一个矩阵,q次操作,每次查询长宽l的矩阵最大值a和最小值b,然后把中间点换成floor((a+b)/2), 解法:暴力可过,建n颗线段树暴力更新,但是正解应该是树套树,树套树需要注意的是当建 ...