Http协议初学

文章目录

参考资料:
IP、TCP和DNS与HTTP的密切关系
实现HTTP协议Get、Post和文件上传功能——设计和模块
HTTP必知必会
HTTP协议 通信过程介绍
图解HTTPS
<<图解HTTP>> 上野宣
全抄袭,仅当监督学习。。。。。。。

##Http协议和TCP、IP协议的关系
我们都知道http协议是一种应用层协议,应用层协议又是什么意思呢?就是要利用下层协议的然后通过自定义一种格式的方式生成了一坨数据然后丢给下一层协议拿去发送(反正我是这么理解的,应该还是对的)。这里的自定义的一种格式就是HTTP协议格式,这里的下一层协议就是TCP协议。且Http协议是一种无连接、无状态的协议,即没有tcp的长连接请求然后响应后理解断开,对事务无记忆能力。


Http协议和其他协议关系

首先是,我想访问网站,将域名发送给DNS去解析,DNS解析后将网站的IP地址返回给客户端,然后通过IP地址发起HTTP请求。HTTP此时的作用是 生成针对目标WEB服务器(我们这里指的是网站的服务器)的HTTP请求报文,然后将请求报文传送给传输层,此时为了方便通信,TCP会将HTTP请求报文 分割成报文段,这些报文段会有一个序号,这里的报文段哪一个先发送哪一个先到达,它们是按序传送的。只要建立起TCP连接,客户端与服务器之间的报文交换就不会丢失,不会被破坏,也不会在接收时出现错序。接着到了网络层,此时IP协议的职责是,搜索对方的地址,一边中转一边传送。然后找到了服务器的位置,此时服务器的传输层中 TCP的职责是 接收到对方传送过来的报文段后,对其进行重组,这里的重组是按序号进行重组的。然后到了服务器的应用层,HTTP会对客户端请求的内容进行处理。处理完后,服务器同样会利用TCP/IP通信协议向客户端进行回传响应。最后客户端收到响应后,将内容输出页面显示。即完成了一次HTTP事务。

##Http消息基本格式
HTTP消息(有的文章称之为报文)分为请求消息和响应消息两种基本分类。其中请求消息是客户端发送给服务器的用于请求服务和资源的消息,响应消息是服务器对请求消息的应答。一般来说,一个响应对应一个请求,不多也不少。

1
2
3
4
5
6
7
8
9
GET /simple.html HTTP/1.1<CRLF>     ----- 首行
Accept: text/html<CRLF> --|
Accept-Language: zh-cn<CRLF> |
Accept-Encoding: gzip, deflate<CRLF> |-- 头部
User-Agent: Mozilla/4.0<CRLF> |
Host: localhost:8080<CRLF> |
Connection: Keep-Alive<CRLF> --|
<CRLF> ----- 空白行表示头部的结束
----- 接下来的内容是正文部分

其中,头部用来指出HTTP消息的一些属性,它们有固定的格式;正文部分是传输的实际内容,它们的格式是任意的,通常用Content-Type头来指定。首行在请求消息和响应消息中具体格式略有区别,它们表示的按理说应该是HTTP消息最基本的部分。不论是HTTP请求还是HTTP响应,首行都是有的,否则会出现不可饶恕的解析错误;然而头部和正文是可选的,不过实际过程中,多多少少都要包含一些基本的头。

##Http请求、响应

###请求

1
2
3
4
5
[首行]请求行       方法 路径 版本  GET /simple.html HTTP/1.1

[头部]请求头部

[正文]请求正文

http请求方法种类很多,但是最常用的就是Get和Post两种。
除Post、Get之外其他http请求

1
2
3
4
5
6
7
8
9
10
方法              描述

GET 请求获取Request-URI所标识的资源
POST 在Request-URI所标识的资源后附加新的数据
HEAD 请求获取由Request-URI所标识的资源的响应消息报头
PUT 请求服务器存储一个资源,并用Request-URI作为其标识
DELETE 请求服务器删除Request-URI所标识的资源
OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求
TRACE 请求服务器回送收到的请求信息,主要用于测试或诊断
CONNECT 把请求连接转换到透明的 TCP/IP 通道。

Get方法
/test/demo_form.asp?name1=value1&name2=value2
Get方法是将数据直接放在URL中发送,Get方法特点如下:

1
2
3
4
5
6
1.GET 传送的数据量较小,不能大于2KB。
2.GET 请求可被缓存
3.GET 请求保留在浏览器历史记录中
4.GET 请求可被收藏为书签
5.GET 请求不应在处理敏感数据时使用
6.GET 请求只应当用于取回数据

Post方法
POST请求可以包含请求正文

1
2
3
4
5
6
7
8
9
POST /test/demo_form.asp HTTP/1.1
Host: w3schools.com
Content-Type: application/json
Content-Length: 38
{"name1": "value1", "name2": "value2"}
1.POST 请求不会被缓存
2.POST 请求不会保留在浏览器历史记录中
3.POST 不能被收藏为书签
4.POST 请求对数据长度没有要求

Get和Post两种方法对比可以发现:
1.Get将请求信息放在URL中安全性较低,可以缓存
2.Get发送长度有限制,适合发送小且不含机密信息的消息,Post将信息放在正文中对长度没有限制(可能具体服务器有限制)
3.Post将将数据封装在报文实体中,而报文的传递会有加密等方法来保证其安全性,所以其安全性自然很高。

###响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
响应行        版本号 状态码 状态文本    HTTP/1.1 200 OK

响应头部

响应正文

HTTP/1.1 404 Not Found 响应行

Date: Mon, 06 Mar 2006 09:03:14 GMT 响应头部
Server: Apache/2.0.55 (Unix) PHP/5.0.5
Content-Length: 291
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> 响应正文
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /notexist was not found on this server.</p>
<hr>
<address>Apache/2.0.55 (Unix) PHP/5.0.5 Server at localhost Port 8080</address>
</body></html>


HTTP的状态响应码
1XX:指示信息,请求收到,继续处理
2XX:成功,操作成功收到,分析,接受
3XX:完成请求必须进一步处理,重定向
4XX:请求包含一个错误语法,不能完成。指示客户端错误
5XX:服务器执行一个有效请求失败,指示服务端错误

##动手实验
客户端直接用vs利用socket通信封装成http消息发送到服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
include "stdafx.h"
#include <winsock2.h>
#pragma comment(lib,"ws2_32")

void HttpPostPacket(char *packet,char *url,char *host,char *data)
{

wsprintfA(packet,"POST %s HTTP/1.1\r\n"
"Accept: */*\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Host: %s\r\n"
"Content-Length: %d\r\n"
"Connection: Keep-Alive\r\n"
"Cookie: ASPSESSIONIDSCDCQCTD=DCOJKBECOHEDIJJGNAPJGOKO\r\n\r\n%s",
url,host,strlen(data),data);
}

int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsaData;
WORD sockVersion = MAKEWORD(2, 2);
//加载winsock库
if(WSAStartup(sockVersion, &wsaData) != 0)
return 0;
// 创建套节字
SOCKET sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sClient == INVALID_SOCKET)
{
printf("socket error\n");
return 0;
}
// 在sockaddr_in结构中装入服务器端地址信息
sockaddr_in servAddr;
servAddr.sin_family = AF_INET;
//设置连接端口
servAddr.sin_port = htons(8080);
//服务器端ip
servAddr.sin_addr.S_un.S_addr =inet_addr("192.168.17.112");
//连接服务器端
if(connect(sClient,(sockaddr*)&servAddr,sizeof(servAddr))==SOCKET_ERROR)
{
printf("connect error\n");
closesocket(sClient);
return 0;
}
char packet[1024];
//提交的URL
char *url="/post";
//服务器域名
char *host="192.168.17.112";
//构造POST数据包
char *PostText="{\"name1\": \"value1\", \"name2\": \"value2\"}";
HttpPostPacket(packet,url,host,PostText);
//发送数据
UINT nSend=send(sClient,packet,strlen(packet),0);
if (nSend<strlen(packet))
{
printf("Send errno %d\n",WSAGetLastError());
}
printf("%s\n\n\n",packet);
char revData[1024]={0};
//接受数据
int ret=recv(sClient,revData,1024,0);
printf("revData:\n%s",revData);
//关闭套接字
closesocket(sClient);
WSACleanup();

getchar();

return 0;
}

服务器端用Python搭建个服务器打印出客户端请求消息并响应,需要使用web库。基本上服务器起的作用就是在指定端口监听tcp连接然后把tcp接收的buf信息(就是http信息)拿出来处理。然后服务器根据http请求的路径信息发到指定的服务器脚本处理比如php脚本的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import web

urls = (
'/get','get_class',
'/post','post_class',
)

# deal get request
class get_class:
def GET(self):
request_data = web.input()
print request_data
return "hello,world!"

#deal post request
class post_class:
def POST(self):
request_data = web.input()
print request_data
data = web.data()
print data
return "hello,world!"

if __name__ == '__main__':
app = web.application(urls, globals())
app.run()

实验结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /post HTTP/1.1
Accept: */*
Content-Type: application/x-www-form-urlencoded
Host: 192.168.17.112
Content-Length: 38
Connection: Keep-Alive
Cookie: ASPSESSIONIDSCDCQCTD=DCOJKBECOHEDIJJGNAPJGOKO

{"name1": "value1", "name2": "value2"}


revData:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Date: Sat, 31 Oct 2015 01:36:00 GMT
Server: localhost

上一篇: Window服务学习笔记
下一篇: 几种创建进程函数的不同