一步步搭建自己的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 ...
随机推荐
- 1568: [JSOI2008]Blue Mary开公司
1568: [JSOI2008]Blue Mary开公司 题目描述 传送门 题目分析 简单分析可以发现就是不停给出了\(n\)条直线,要求每次给出一条直线后求出所有直线在横坐标为\(x\)时\(y\) ...
- Graph_Master(连通分量_D_Trajan缩点+dfs)
hdu_2242 题目大意:求将一张无向图(n个点,m条边)移除一条边分为不连通两部分,使得两部分的点权和最接近,若无法分为两部分,则输出impossible. 题解:拿到题面还算清晰,就是先tarj ...
- jquery 弹窗插件 layer 常见接口
源自:https://www.cnblogs.com/teamobaby/p/3556584.html 常见接口如下: 方法名 描述 $.layer({}) 核心接口,参数是一个对象,对象属性参见上述 ...
- spring boot 知识点1
spring boot: 1. 可以在pom文件中添加依赖sping-boot-properties-migrator来对项目进行升级,升级完成后,删除即可. 2. 关于日志的配置,参考:http:/ ...
- C5 标准IO库:APUE 笔记
C5 :标准IO库 在第三章中,所有IO函数都是围绕文件描述符展开,文件描述符用于后续IO操作.由于文件描述符相关的操作是不带缓冲的IO,需要操作者本人指定缓冲区分配.IO长度等,对设备环境要求一定的 ...
- JavaScript清除字符串前后空格
一.通过循环检查,然后提取非空格字符串 //去掉前后空白 function trim(s){ return trimRight(trimLeft(s)); } //去掉左边的空白 function t ...
- R-模式(mode)和类(class)
数据模式:mode函数显示任何对象的模式.常见的单个的对象模式是逻辑型(Logical).数值型(Numeric).字符型(Character). 常用到的数据模式是列表(list). 逻辑型:TRU ...
- selenium的三种等待时间设置
为了提高脚本的稳定性,我们需要在脚本中增加等待时间 第一种:强制等待 Thread.sleep():固定休眠时间设置,Java的Thread类里提供了休眠方法sleep,导入包后就能使用 sleep( ...
- hduacm集训单人排位赛1002
自适应simpson积分公式 通过二分区间递归求simpson积分 #include<map> #include<set> #include<cmath> #inc ...
- hdu3863找规律
先画一下N=2的情况,先手胜,再画一下N=3的情况,先手胜,所以大胆的猜测,无论N=多少,先手胜!! 这也能A真是个奇迹 #include<map> #include<set> ...