5.2.1 HTTP协议
全称HyperText Transfer Protocol,中文叫做超文本传输协议,它是一个应用层协议,基于TCP,默认使用80端口,传输超文本格式数据。超文本的意思是这种文本既适合人阅读,也适合计算机处理。
请求和应答
当客户端和服务器通信时,客户端发送的报文叫做请求,服务器回应的报文叫做应答。
用户代理(user agent)
当客户端发起请求时,发送请求的程序,叫做用户代理,常见的代理就是浏览器,比如chrome、firefox、IE等等
应答服务器
应答服务器保存着图片和html网页资源,当收到代理的请求时,服务器根据请求,响应给客户相应资源。常用的HTTP服务器软件有apache,iis,nginx等等。
请求和应答格式
请求格式:
GET / HTTP/1.1
Host: 127.0.0.1
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
应答格式:
HTTP/1.1 200 OK
Date: Mon, 25 Apr 2016 15:29:54 GMT
Server: Apache/2.4.7 (Ubuntu)
Last-Modified: Mon, 25 Apr 2016 15:22:50 GMT
ETag: "29-53150bfe5bf20"
Accept-Ranges: bytes
Content-Length: 41
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html
hello, this is a page from ubuntu/apache
请求和应答格式详解
请求格式:
字段 | 含义 |
---|---|
GET / HTTP/1.1 | 客户端告诉服务器,这个请求是一个是个GET方法,使用协议HTTP 1.1,客户端向服务器的请求有GET、POST等方法,协议也有1.0,2.0等协议 |
Host: 127.0.0.1 | 客户端告诉服务器,客户端访问的站点名字,以前服务器比较贵(现在也贵),一台服务器往往会布置多个网站,比如www.aaa.com和www.bbb.com都在一起时,这个字段就有用了 |
Connection: keep-alive | 客户端告诉服务器,连接要保持,不要断掉,客户端等会儿还要有数据来(其实是没有了,协议规定了如此),历史上HTTP设计用来做简单应答的,就是客户端请求啥,服务器给啥,然后大家就拜拜了。但是这样的话每次请求都是一次新的连接,比较恼火,然后聪明人就发明了keep-alive这种东西。在http1.0中,这个属性是可选的,但是在http1.1中,这个字段总是规定存在。 |
Accept: text/html,... | 客户端告诉服务器,客户端这边能接收的数据格式是什么 |
Upgrade-Insecure-Requests: 1 | 客户端告诉服务器,升级安全请求,这个和安全相关 |
User-Agent: Mozilla/5.0 ... | 客户端告诉服务器,用户代理是什么,服务器可以根据不同的代理,做出不同响应 |
Accept-Encoding: gzip, deflate, sdch | 客户端告诉服务器,支持的编码是什么,直接传输比较大,可以使用gzip压缩一下的 |
Accept-Language: zh-CN,zh;q=0.8 | 客户端告诉服务器,客户端支持的语言 |
应答格式
字段 | 含义 |
---|---|
HTTP/1.1 200 OK | 服务器应答:成功 服务器应答如果是200,表示完全成功,一点儿问题都没有,服务器的应答编码有很多,这个应答也是将来排除代码bug的重要依据,应答机也记不住那么多,但是分类分得很好 1xx 表示临时性应答 2xx 表示正确 3xx 表示重定向 4xx 表示客户端错误 5xx 表示服务器错误 具体可以看以下博文 http://blog.sina.com.cn/s/blog_5677f07c0101a7pn.html |
Date: Mon, 25 Apr 2016 15:29:54 GMT | 服务器日期时间 |
Server: Apache/2.4.7 (Ubuntu) | 服务器 |
Last-Modified: Mon, 25 Apr 2016 15:22:50 GMT | 所请求资源的最后修改日期 |
ETag: "29-53150bfe5bf20" | 客户端请求一个页面(A)。 服务器返回页面A,并在给A加上一个ETag。 客户端展现该页面,并将页面连同ETag一起缓存。 客户再次请求页面A,并将上次请求时服务器返回的ETag一起传递给服务器。 服务器检查该ETag,并判断出该页面自上次客户端请求之后还未被修改,直接返回响应304(未修改——Not Modified)和一个空的响应体。 |
Accept-Ranges: bytes | 告诉客户端,服务器支持区间,意味着客户端可以请求部分资源,请求部分资源就意味着支持断点续传 |
Content-Length: 41 | 内容长度 |
Keep-Alive: timeout=5, max=100 | 回答客户端的keepalive,告诉客户端,五秒内必须要数据,不然我关闭连接,再有就是你这个连接最多来100个报文,满100个之后也关闭 |
Connection: Keep-Alive | |
Content-Type: text/html | 服务器响应数据的内容类型是text/html |
hello, this is a page from ubuntu/apache |
获取请求报文代码
#include <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#define myerror(__err) do{perror(__err);exit(0);}while(0)
int main(int argc, char* argv[])
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(80);
addr.sin_addr.s_addr = 0;
int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
if(ret < 0)
myerror("bind");
listen(fd, 5);
int newfd = accept(fd, NULL, NULL);
char buf[2048];
recv(newfd, buf, sizeof(buf), 0);
printf("%s\n", buf);
return 0;
}
获取应答报文代码
#include <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#define myerror(__err) do{perror(__err);exit(0);}while(0)
int main(int argc, char* argv[])
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(80);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
int ret = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
if(ret < 0)
myerror("connect");
char buf[] = "GET / HTTP/1.1\n"
"Host: 127.0.0.1\n"
"Connection: keep-alive\n"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\n"
"Upgrade-Insecure-Requests: 1\n"
"User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36\n"
"Accept-Encoding: gzip, deflate, sdch\n"
"Accept-Language: zh-CN,zh;q=0.8\n\n";
send(fd, buf, sizeof(buf), 0);
char resp[4096];
recv(fd, resp, sizeof(resp), 0);
printf("%s\n", resp);
pause();
return 0;
}