HTTP协议
# 前言
HTTP(超文本传输协议)协议是处于应用层的协议
应用层协议
协议其实就是一种约定
应用层协议是程序员自己写的
HTTP是无状态协议
HTTP无状态协议,是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就比较快
# 两种用于保持HTTP连接状态的技术
Cookie和Session可以支持客户端和服务器之间的交互
Cookie:通过客户端保持状态。Cookie就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放在客户端,然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息
当用户使用浏览器访问一个支持Cookie的网站的时候,用户会提供包括用户名在内的个人信息并且提交至服务器,接着服务器在向客户端回传相应的超文本的同时也会发挥这些个人信息,当然这些信息不是存放在HTTP的响应体(Response Body)中的,而是存放在HTTP响应头(Response Header);当客户端浏览器接收到来自服务器的响应之后,浏览器会将这些信息存放在一个统一的位置。对于Windows操作系统来说,我们可以从:[系统盘]:\Documents and Settnigs[用户名]\Cookies目录找到存储的Cookie;自此客户端在向服务器发送请求的时候,都会把相应的Cookie再次发送至服务器。而这次Cookie信息则存放在HTTP请求头(Request Header)了
Session(会话):通过服务器来保持状态的。
要使用Session必须要先创建Session。是在服务端程序运行的过程中创建的,不同的语言有不同创建Session的方法。再创建Session的同时,服务器会为该Session创建唯一的Session id,而这个Session id在随后的请求中会被用来重新获得已经创建好的Session,在Session被创建之后,就可以调用Session相关的方法往Session中增加内容了,而这些内容只会保存在服务器中,发到客户端的只有Session id;当客户端再次发送请求的时候,会将这个Session id带上,服务器接收到请求之后就会依据Session id找到相应的Session,从而再次使用它,正是这样的一个过程,用户的状态也就得以保持了
综上所述,HTTP本身是一个无状态的连接协议,为了支持客户端和服务器之间的交互,为我们需要通过不同的技术为交互存储状态,而这些不同的技术就是Cookie和Session了
# URL的认识
URL就是网址
插图:URL详解
【注意】
?前面的是要访问的资源
?后面的是传递给服务器的相关参数
URL有目录表示服务器使用Linux实现:该目录是Web服务器的目录,一般不是根目录
片段标识符:网页中内嵌的元素,有可能是第几个
urlencode和urldecode
对于像/ ? :这样的字符已经被url当做特殊意义的字符进行处理了,所以这些字符不能轻易的出现。
但是对于有的参数中必须有这样的字符的时候,就必须对这些字符进行转义
转义的规则
将需要进行转码的字符转为16进制,然后从右到左,取4位(不足四位直接处理),每2位做一位,前面加上%,编码成%XY的形式
例如:在百度搜索C++的时候,"+"就会被转义为"%2B"
urldecode即使urlencode的逆过程
其实这也就是一个序列化和反序列化的过程
# HTTP协议的格式
对于HTTP的请求和响应一般分为三到四部分
HTTP请求
请求行
方法+url+版本
请求报头
以行为单位的
使用key:value来表示。key代表属性,value代表信息
空行
将报头和有效载荷进行分离
请求正文
一般是用户名和密码
请求报文可以是空字符串,但是如果存在的话,那么在报头中就要有着一个Content-Length属性来标识请求报文的长度
HTTP响应
状态行
版本号+状态码+状态码解释
响应报头
以行为单位
使用key:value来表示。key代表属性,value代表信息
空行
将报头和有效载荷进行分离
响应正文
响应正文可以是空字符串,但是如果存在的话,那么在报头中就会有着一个Content-Length属性来标识响应正文的长度
# HTTP的方法
方法 说明 支持的HTTP协议版本 GET 获取资源 1.0、1.1 POST 传输实体主体 1.0、1.1 PUT 传输文件 1.0、1.1 HEAD 获得报文首部 1.0、1.1 DELETE 删除文件 1.0、1.1 OPTIONS 询问支持的方法 1.1 TRACE 追踪路径 1.1 CONNECT 要求用隧道协议连接代理 1.1 LINK 建立和资源之间的关系 1.0 UNLINE 断开连接关系 1.0
其中最常用的就是GET和POST方法
GET和POST都是请求数据
GET和POST的区别:POST提交数据在正文中、GET提交数据在url中
GET中url是长度是有限的,具体有多长()
# HTTP的状态码
类别 原因短语 1XX Informational(信息性状态码) 接收的请求正在处理 2XX Success(成功状态码) 请求处理完毕 3XX Rediection(重定向状态码) 需要进行附加操作以完成请求 4XX Client Error(客户端错误状态码) 服务器无法处理请求 5XX Server Error(服务器错误状态码) 服务器处理请求出错
常见的错误码
200(OK),404(Not Found),403(Forbidden),302(Redirect重定向),504(Bad Gateway)
重定向
302,307:临时重定向
301:永久重定向
403(禁止):服务器拒绝请求。服务器找不到请求的网页。例如:对于服务器上不存在的网页经常会返回此代码
404(未找到):对于浏览器抓取的网址看到此状态吗,则表示浏览器跟随的可能是另一个页面的无效链接(旧链接或者输入有误的链接)
504(网管超时):服务器作为网管或者代理,但是没有从上游服务器收到请求
# HTTP常见的报头
Content-Type
数据类型
User-Agent
声明用户的操作系统和浏览器版本信息
对于每一个请求的User-Agent都有一个Mzilla字样这是为什么呢?
Content-length
正文的长度(长链接下需要知道正文的长度)
Host
客户端告诉服务器所请求的资源是在那个主机的那个服务器上
referer
当前页面是从那个页面跳转过来的
location
搭配3XX状态码使用,告诉客户端接下来要去哪里访问呢
Cookie
用于客户端存储少量的信息,通常用于实现会话(Session)的功能。存放账号密码,昵称,基本信息
好处
再次登陆的时候服务器的时候就会把Cookie文件带上就不需要再次输入账号和密码了
坏处
来一个木马病毒,把Cookie文件带走了,然后放到自己的服务器所存储的文件中,病毒登陆的时候直接把Cookie文件也带上去,登录服务器就不需要密码了这样密码就会被盗了
解决方法:把账号和密码放到服务器上,让服务器给客户端返回一个Session ID,这个ID存储到自己的Cookie中,每次登陆的时候使用ID获取密码登录。虽说还是可以被盗号,但是对于Session ID有着自己的存活周期,过几个小时就没有了,就无法登录了对被人来说。但是对于自己再次登录需要账号和密码
keep-alive
长链接(是否正常链接)
对于旧版的浏览器拿网页要拿五张照片的话,必须依次一次一次一张照片的拿过程是这样的
建立连接->那资源->断开连接,循环执行,再次建立连接。这样的话就会导致建立多次连接,对于建立连接是需要成本的,所以这样的话就会导致浪费较多的成本
而对于长链接就是每次建立一个TCP连接,可以在这一个TCP连接上发送多条消息,不会让发送一次消息就断开连接再次重新连接。这样的话,就会大量减少建立连接所造成的成本损耗,即TIME_WAIT的状态连接少了。减少了系统内核调用,socket的accept()和close()的调用。
使用keep-alive必须要将keep-alive timeout时间设置好。
http的守护进程一般都提供了keep-alive timeout时间设置参数。
keep-alive timeout:一个HTTP产生的TCP连接传输完最后一个响应后,还需要保持住keep-alive timeout秒后,才开始关闭这个链接。
也就是当HTTP守护进程发送完一个响应之后,理应马上主动关闭响应的TCP连接,设置keep-alive timeout后,HTTP守护进程会说:”再等等看,看浏览器还有没有请求发送过来“,这一等就是keep-alive timeout时间。如果守护进程在这个等待的时间里,一直没有收到浏览器发送过来的请求,就关闭这个链接
对于keep-alive模式下,如何确定响应的数据已经接收完了呢?
使用Content-Length表示正文长度,客户端(服务器)可以根据这个值来判断数据时候接收完毕
Accept
对于服务器来说,可以接受哪些资源
# 最简单的HTTP服务器
实现一个简单的HTTP也就是对于应用层只需要遵循HTTP协议,对于传输层使用TCP协议就好了
应用层遵循HTTP协议
也就是对于客户端和服务器端发送的消息必须是HTTP协议的请求和响应报文
传输层遵循TCP协议
也就是对于客户端和服务器端传输消息的方式必须是先建立连接才能发送消息
实现一个可以在Web端可以输出一个hello world的消息
当我们使用chrome测试我们的服务器的时候,可以看到服务器打出的请求中还有一个
GET /favicon.ico HTTP/1.1
这样的请求
favivon.ico
:是网站图标,如果不设置浏览器就会请求网站根目录的这个图标代码链接:
https://github.com/YKitty/LinuxDir/tree/master/LinuxCode/netWork/HTTP
# 知识点
空行可以判断报头读完了吗,Content-Length用来判断正文读完了吗
一个端口号每次只能被一个进程所绑定
由TIME_WIAT体现出来(反例)
当关闭一个服务器的时候,不能立马再次启动这个服务器,这是因为该服务器处于TIME_WAIT状态,对于端口号还没有释放呢,所以无法立马再次启动相同端口号的服务器
解决方法:
使用端口复用,调用setsockopt()函数就可以了
使用方法:
bool bReuseaddr = true; setsockopt(socket, SOL_SOCKET,so_REUSEADDR, (cnost char*)&bReyseaddr, sizeof(bool));
网站访问量
IP访问量:相同的公网IP计算一次,就是同一个局域网的所有用户访问同一个网站,但是他们都是借助一个公网IP去访问那个网站的NAT,因此这也只能算一个IP访问量。换一次公网IP则会加1
PV 网页访问量:用户访问的页面数就是PV访问量,同一个局域网的不同用户,而且就算是同一用户,只要刷新一次网站网页,PV访问量就加1,三个访问量的值往往PV的值最大
UV 访客访问量:这里的访客不是用户,而是电脑,一台电脑算一个访客,即使是同一台电脑的不同用户,访问同一个网站也只能加1,只有更换电脑才会是UV加1,因此服务器会记录客户端电脑的信息
最后再附上自己实现HTTP服务器的代码链接:
https://github.com/YKitty/LinuxDir/tree/master/LinuxCode/netWork/HTTP