HTTP协议--MyWebServer
HTTP协议
HTTP协议是一种Web通信协议,通过特定的规则来实现服务器跟客户端的通信。HTTP协议有这样几个特点:
(1)面向无连接的,一次只能处理一个请求,HTTP1.0服务器解析完客户端请求并作出应答后,会关闭连接;对于HTTP1.1应答后会等待一个非常短的时间,如果这段时间没有新请求,就会关闭连接。
(2)HTTP协议是无状态的,即对处理过的事务没有记忆能力,它认为每一次请求都是陌生的独立的,为了解决这个问题,Web服务程序引进了cookie机制来维持请求状态。
(3)HTTP协议允许传输任意类型的数据,对于正在传输的数据类型用Content-Type标记。
URL
url需要提供几种信息,一是采用的协议,二是连接的套接字,三是请求文件的路径,后面还可以跟上请求参数
在浏览器中输入www.csdn.net,浏览器会自动帮我们转化为http://www.csdn.net/。
采用的协议,这里已HTTP为例;连接套接字包括ip地址跟端口号,端口号一般都是默认的,不需要我们输入,ip地址我们一般输入域名,然后通过域名服务器解析;请求的路径,一般web程序会提供一个默认路径,如果不输,就是默认的;路径后面还可以跟上GET请求的参数,在请求路径后加上"?"参数之间用“&”连接。一般来说简单的无安全要求的数据,我们直接通过GET方法传递给服务器,而大量的隐私的数据我们通过Post方法传递给服务器。
HTTP请求报文
请求报文分为三个部分,请求行、请求头、请求体,格式都是固定的。如图1.1所示:
请求的方法如下:
(1)GET 请求获取url标识的资源
(2)POST 请求获取url标识的资源并像浏览器传递数据
(3)HEAD 请求服务器对url的响应报头
(4)PUT 请求服务器存储资源,并以url作为其标识
(5)DELETE 请求服务器删除url标识的资源
(6)TRACE 请求服务器返回发送过去的请求,主要用于诊断和测试
HTTP响应报文
响应报文也分为三个部分,响应行、响应头、响应体,如图1.2所示:
响应行包含了协议版本,状态码,和状态码的描述。
状态码是一个百位数,100段表示请求已接受,继续处理;200段表示请求成功;300段表示请求需要做进一步处理,比如说跳转;400段表示请求错误,并且是客户端的原因;500段表示服务器的原因导致了请求错误。
常见的响应码如下:
200 : OK
302 : Found 重定向
400 : Bad Request 错误请求,发出错误的不符合Http协议的请求
401 : Unauthorized 请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 : Forbidden 禁止
404 : Not Found 未找到
500 : Internal Server Error 服务器内部错误
503 : Service Unavailable 一般是访问人数过多
常用的类型名:
Server 提供web服务器版本信息;Content-Type 响应的内容的类型 ;Content-Length 响应体的字节长度 ;Connetion 连接的方式信息 ;Accept-Ranges 接收数据的方式,通常是字节数组。
MyWebServer
复习,模拟一个自己的简单服务器程序,步骤如下:
1、接收浏览器发送的请求(socket)
2、分析请求报文(http),请求的路径
3、生成响应报文,响应体
4、发送响应内容
//用的winform,首先搭建一个窗体,点击开始后开始监听。
- namespace MyWebServer
- {
- public partial class Form1 : Form
- {
- public Form1()
- {
- InitializeComponent();
- Control.CheckForIllegalCrossThreadCalls = false;
- }
- void ShowMsg(string str)
- {
- txtLog.AppendText(str+"\r\n");
- }
- private void btnStart_Click(object sender, EventArgs e)
- {
- //点击开始运行,创建一个socket对象并进行监听
- IPAddress ip;int p;
- if (!IPAddress.TryParse(txtIp.Text, out ip))
- {
- MessageBox.Show("请输入一个正确的ip地址");
- return;
- }
- if(!int.TryParse(txtPort.Text,out p))
- {
- MessageBox.Show("请输入一个正确的端口号");
- return ;
- }
- IPEndPoint point = new IPEndPoint(ip, p);
- Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- try
- {
- socket.Bind(point);//绑定地址
- socket.Listen(10);//开始监听
- ShowMsg("开始运行。。。");
- //创建一个后台线程接受客户端的连接
- Thread th = new Thread(Listen);
- th.IsBackground = true;
- th.Start(socket);
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message);
- }
- }
- private void Listen(object o)
- {
- Socket socket = o as Socket;
- while (true)
- {
- Socket connSocket = socket.Accept();//通信用的socket
- ShowMsg(connSocket.RemoteEndPoint + "连接成功");
- //创建一个DataConnection类专门接收请求和发送响应
- DataConnection dc = new DataConnection(connSocket, ShowMsg);
- }
- }
- }
- }
其中接收和发送请求交给DataConnection
- namespace MyWebServer
- {
- delegate void DelHandler(string str);//用于传递方法ShowMsg
- class DataConnection
- {
- Socket connsocket; DelHandler del; string request;
- public DataConnection(Socket socket,DelHandler del)
- {
- connsocket=socket;
- this.del = del;
- request = RecRequest();
- del(request);//通过委托调用窗体的ShowMsg方法,显示请求报文
- //分析请求报文,放在Request类中进行
- Request req = new Request(request);
- staticPage(req.Url);
- }
- //处理静态页面,根据请求的路径来判断
- void staticPage(string url)
- {
- string extension = Path.GetExtension(url).TrimStart('.');//获取后缀名
- switch (extension)
- {
- case "html":
- case "htm":
- case "css":
- case "js":
- case "jpg":
- case "png":
- case "gif":
- //处理静态页面,生产响应有Response类负责
- ProcessStaticPage(url);
- break;
- case"she":
- //处理动态页面
- break;
- default:
- break;
- }
- }
- //处理静态页面
- void ProcessStaticPage(string url)
- {
- //求出绝对路径
- string path = AppDomain.CurrentDomain.BaseDirectory + url;
- //判断文件是否存在
- if (File.Exists(path))
- {
- using (FileStream fs=new FileStream(path,FileMode.Open))
- {
- //读取文件
- byte[]buffer=new byte[fs.Length];
- fs.Read(buffer, 0, buffer.Length);
- //生成响应头,交给Response类
- Response response = new Response(200, buffer.Length, url);
- connsocket.Send(response.GetResponseHeads());
- connsocket.Send(buffer);
- connsocket.Close();
- del("关闭了连接");
- }
- }
- else
- {
- //文件不存在,404页面
- }
- }
- void ProcessDTPage(string url)
- {
- string fileName = Path.GetFileNameWithoutExtension(url);//一般把文件名定义成类名
- //获取当前方法所在的命名空间
- string nameSpace = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace;
- //类的全名称
- string fullName = nameSpace + "." + fileName;
- IHttpHandler handler = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(fullName, true) as IHttpHandler;
- if (handler != null)
- {
- //响应体
- byte[] buffer = handler.ProcessRequest();
- //响应头
- Response res = new Response(200, buffer.Length, url);
- //发送
- connsocket.Send(res.GetResponseHeads());
- connsocket.Send(buffer);
- connsocket.Close();
- del("关闭连接");
- }
- }
- //接收请求报文
- string RecRequest()
- {
- byte[] buffer = new byte[1024 * 1024];
- int num=connsocket.Receive(buffer);
- return Encoding.UTF8.GetString(buffer,0,num);
- }
- }
- }
分割请求信息得到路径和准备响应头都交给对应的类做了:
- class Request
- {
- string request; public string Url;
- public Request(string request)
- {
- try
- {
- string[] strs = request.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
- string first = strs[0];
- string[] requstHeads = first.Split( ' ');
- Url = requstHeads[1];//请求行中的路径
- }
- catch (Exception ex)
- {
- Url = "";
- }
- }
- }
- class Response
- {
- Dictionary<int, string> dic = new Dictionary<int, string>();//存状态码根描述
- int stateCode = 200;
- int contentLength;
- string contentType;
- public Response(int stateCode,int contentLength,string url)
- {
- Fill();
- this.stateCode = stateCode;
- this.contentLength = contentLength;
- GetContentType(url);
- }
- //生成响应头
- public byte[] GetResponseHeads()
- {
- StringBuilder sb = new StringBuilder();
- sb.AppendLine("HTTP/1.1 "+stateCode+" "+dic[stateCode]);
- sb.AppendLine("Content-Length: " + contentLength);
- sb.AppendLine("Content-Type: "+ contentType +";charset=utf-8\r\n");
- return Encoding.UTF8.GetBytes(sb.ToString());
- }
- //根据后缀给contenttype赋值
- void GetContentType(string url)
- {
- //.htm
- string ext = Path.GetExtension(url);
- switch (ext)
- {
- case ".htm":
- case ".html":
- contentType = "text/html";
- break;
- case ".css":
- contentType = "text/css";
- break;
- case ".js":
- contentType = "text/javascript";
- break;
- case ".jpg":
- contentType = "image/jpeg";
- break;
- default:
- contentType = "text/html";
- break;
- }
- }
- void Fill()
- {
- dic.Add(200, "OK");
- dic.Add(400, "Not Found");
- }
- }
HTTP协议--MyWebServer的更多相关文章
- HTTP协议系列(1)
一.为什么学习Http协议 首先明白我们为什么学习HTTP协议,也就是说明白HTTP协议的作用.HTTP协议是用于客户端与服务器之间的通讯.明白了HTTP协议的作用也就知道了为什么要学习H ...
- 重温Http协议--请求报文和响应报文
http协议是位于应用层的协议,我们在日常浏览网页比如在导航网站请求百度首页的时候,会先通过http协议把请求做一个类似于编码的工作,发送给百度的服务器,然后在百度服务器响应请求时把相应的内容再通过h ...
- 协议森林17 我和你的悄悄话 (SSL/TLS协议)
作者:Vamei 出处:http://www.cnblogs.com/vamei 转载请先与我联系. TLS名为传输层安全协议(Transport Layer Protocol),这个协议是一套加密的 ...
- 协议森林16 小美的桌号(DHCP协议)
作者:Vamei 出处:http://www.cnblogs.com/vamei 转载请先与我联系. DHCP协议用于动态的配置电脑的网络相关参数,如主机的IP地址,路由器出口地址.DNS域名服务器地 ...
- 简约之美Jodd-http--深入源码理解http协议
Jodd 是一个开源的 Java 工具集, 包含一些实用的工具类和小型框架.简单,却很强大! jodd-http是一个轻巧的HTTP客户端.现在我们以一个简单的示例从源码层看看是如何实现的? Http ...
- 【JavaScript】javascript中伪协议(javascript:)使用探讨
javascript:这个特殊的协议类型声明了URL的主体是任意的javascript代码,它由javascript的解释器运行. 比如下面这个死链接: <a href="javasc ...
- SNMP简单网络管理协议
声明:以下内容是学习谌玺老师视频整理出来(http://edu.51cto.com/course/course_id-861.html) SNMP(Simple Network Management ...
- 海鑫智圣:物联网漫谈之MQTT协议
什么是MQTT协议 MQTT(消息队列遥测传输协议)是IBM在1999年专门针对物联网等应用场景来制订的轻量级双向消息传输协议,它主要是为了解决物联网上使用到的设备的互相通信的问题,以及这些设备与后端 ...
- linux-图形化远程管理协议
远程管理控制方式: RDP(remote desktop protocol)协议: telnet: SSH(Secure Shell): RFB(Remote FrameBuffer)协议(图形化远程 ...
随机推荐
- Sqlserver在现有数据库中插入数据
需求:1.客户提供的excel表和数据库中的表结构总是有一些差距,id的生成,各种字段的关联等等 2. 如何在Excel中生成Guid. 1.在Excel的宏中执行以下代码: Private Decl ...
- 在k8s集群中,利用prometheus的jmx_exporter进行tomcat的JVM性能监控,并用grafana作前端展示
查找了很多文档,没有完全达到我要求的, 于是,作了一定的调整,成现在这样. 操作步骤如下: 一,准备好两个文件. jmx_prometheus_javaagent-0.3.1.jar jmx_expo ...
- Git(二)使用git管理文件版本(TortoiseGit )
一.创建版本库 什么是版本库呢?版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改.删除,Git都能跟踪,以便任何时刻都 ...
- php实现https(tls/ssl)双向认证
php实现https(tls/ssl)双向认证 通常情况下,在部署https的时候,是基于ssl单向认证的,也就是说只要客户端认证服务器,而服务器不需要认证客户端. 但在一些安全性较高的场景,如银行, ...
- 【LOJ】#6434. 「PKUSC2018」主斗地
题解 什么,我这题竟然快到了LOJ rk1???? 搜起来有点麻烦,不过感觉还是比斗地主好下手(至今没敢写斗地主 首先是暴力搜牌型,最多\(3^{16}\)(什么判解还要复杂度怂成一团)的样子?? 然 ...
- date命令使用文档
date命令的帮助信息 [root@localhost source]# date --help用法:date [选项]... [+格式] 或:date [-u|--utc|--universal] ...
- PHP函数之trigger_error
在程序开发中,如果我们编码不规范,比如调用不存在的变量.语法错误.少了个逗号,这些都会引起系统报错并进行提示,但是今天,突然发现PHP还有这样一个函数,用于自动触发一个报错提示,并且会将报错信息写入p ...
- 访问url下载文件----python
工作上有时候有需求,会下载pdf,doc,zip等文件,可以用以下方法,推荐使用第一种 下载文件: import urllib import urllib2 import requests url = ...
- centos7 firewall 相关
1.centos 6 是iptables, 7 开始就以firewalld代替iptables; 2.systemctl stop firewalld.service 停 systemctl sta ...
- springmvc配置MappingJackson2HttpMessageConverter实现属性驼峰和下划线的转换
需求 php调用java接口时,因为php那边的属性都是下划线风格,java这边的属性都是驼峰的风格.配置springmvc的json转换,在requestBody的时候(调用对象的set 方法)将j ...