目录
一、什么是HTTP协议
1.HTTP协议:即超文本传输协议,是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。
2.HTTP是基于TCP的应用层协议,它不关心数据的传输细节,主要用来规定客户端和服务器端的数据传输格式。设计HTTP最初
的目的是为了提供一种发布和接收HTML页面的方法。
3.HTTP默认是80端口。
二、认识URL
1.URL,统一资源定位符,是互联网上用来表示某一资源的地址。平时我们说的的 "网址" 其实就是说的 URL。
2.格式:
3.解释
协议方案名:表示使用的协议,可为HTTP,HTTPS,FTP等。
服务器地址:可以为域名,也可以是IP地址。
端口号:跟在域名后面,用冒号分开,如果省略,就采用默认端口。
查询字符串:从?到#之间的是参数。多个参数之间用&作为分隔符。
三、urlencode和urldecode
1.urlencode编码
搜索C++会发现url中变成了C%2B%2B,这是由于像 / ? : 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出
现. 比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义。
转义规则:
将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY。
2.urldecode解码
是urldecode就是urlencode的逆过程,将%XY转义成正常的字符。这个一般网上的工具可以直接翻译。
四、HTTP请求和响应
1.HTTP请求:
HTTP请求包含四部分:
请求首行: [方法] + [url] + [版本]
请求报头: 请求的属性, 冒号分割的键值对,每组属性之间使用\n分隔(如下图所示)
空行:遇到空行表示Header部分结束
请求正文: 空行后面的内容都是正文,允许为空. 如果正文存在, 则在报头中会有一个Content-Length属性来标识其的长度;
2.HTTP响应
HTTP响应包含四部分:
首行:[版本号] + [状态码] + [状态码解释]
相应报头: 请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔;
空行:遇到空行表示Header部分结束
正文: 空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有一个Content-Length属性来标识
Body的长度; 如果服务器返回了一个html页面, 那么html页面内容就是在body中.
3.HTTP常见方法
这里要注意的是GET和POST的区别,详情见:https://blog.csdn.net/a_struggling_monkey/article/details/89239983
4.HTTP常见报头
Content-Type: 区分有效载荷的类型(text/html等)
User-Agent: 声明用户的操作系统和浏览器版本信息;
Content-Length: Body的长度
Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
referer: 当前页面是从哪个页面跳转过来的;
location: 搭配3xx状态码使用, 告诉客户端接下来要去哪里访问;
Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;
Accept:告诉服务器,客户端可以接受什么样的资源
问题:session和cookie的区别?
Session 是服务器用来跟踪用户的一种手段,每个 Session 都有一个唯一标识:Session ID。当服务器创建了一个 Session 时,
给客户端发送的响应报文就包含了 Set-Cookie 字段,其中有一个名为 sid 的键值对,这个键值对就是 Session ID。客户端收到
后就把 Cookie 保存在浏览器中,并且之后发送的请求报文都包含 Session ID。HTTP 就是 Session 和 Cookie 这两种方式一起
合作来实现跟踪用户状态的,而 Session 用于服务器端,Cookie 用于客户端。
5.HTTP常见状态码
最常见的状态码, 比如 200(OK), 404(Not Found), 403(Forbidden), 302(Redirect, 重定向), 504(Bad Gateway)
更多:https://www.cnblogs.com/zt123123/p/8327706.html
五、HTTP服务器的实现
实现一个最简单的HTTP服务器, 只在网页上输出 "hello world",只要我们按照HTTP协议的要求构造数据, 就很容易能做到。
1 #include<sys/socket.h>
2 #include<stdio.h>
3 #include<string.h>
4 #include <unistd.h>
5 #include<stdlib.h>
6 #include<netinet/in.h>
7 #include<arpa/inet.h>
8 void Usage()
9 {
10 //./a.out ip port
11 printf("usage:./server[ip] [port]\n");
12 }
13 int main(int argc,char* argv[])
14 {
15 if(argc!=3)
16 {
17 Usage();
18 return 1;
19 }
20 //创建socket ipv4 面向字节流
21 int fd=socket(AF_INET,SOCK_STREAM,0);
22 if(fd<0)
23 {
24 perror("socket");
25 return 1;
26 }
27 //服务器端地址
28 struct sockaddr_in addr;
29 addr.sin_family=AF_INET;//协议族
30 addr.sin_addr.s_addr=inet_addr(argv[1]);//ip转成四字节大端
31 addr.sin_port=htons(atoi(argv[2]));
32
33 //绑定服务器端口
34 int ret=bind(fd,(struct sockaddr*)&addr,sizeof(addr));
35 if(ret<0)
36 {
37 perror("bind");
38 return 1;
39 }
40
41 //监听
42 ret=listen(fd,10);
43 if(ret<0)
44 {
45 perror("listen");
46 return 1;
47 }
48 printf("listen sucucess....");
49 //循环等待链接
50 for(;;)
51 {
52 struct sockaddr_in client_addr;
53 socklen_t len=sizeof(client_addr);
54 int client_fd=accept(fd,(struct sockaddr*)&client_addr,&len);
55 if(client_fd<0)
56 {
57 perror("accept");
58 continue;
59 }
60 printf("Get Connect[%s]:[%d]\n",inet_ntoa(client_addr.sin_addr),ntohs(cli ent_addr.sin_port));
61 char input_buf[1024*10]={0};
62 ssize_t read_size=read(client_fd,input_buf,sizeof(input_buf)-1);
63 if(read_size<0)
64 {
65 perror("read");
66 return 1;
67 }
68 printf("[Request] %s",input_buf);
69 char buf[1024]={0};
70 const char* hello="hello world";
71 sprintf(buf,"HTTP/1.1 200OK\nContent-Length:%lu\n\n%s",strlen(hello),hell o);
72 if(write(client_fd,buf,strlen(buf))<0)
73 {
74 perror("write");
75 return 1;
76 }
77 }
78 close(fd);
79 return 0;
80 }
结果: