什么是HTTP协议,HTTP协议有什么作用?
- 首先HTTP协议属于应用层协议,应用层的协议就是我们 程序员自己定的,但是,如果每次都要我们程序员自己定协议,又麻烦而且容易出错(自己什么水平自己应该有点数( ̄_ ̄|||)),最重要的是有大佬已经定义了一些现成的(HTTP,DNS等),所以大多时候我们都是直接拿来用,而应用层的作用就是双方达成某种约定,一端按照约定的协议发送数据,另一端按照约定来解析数据,保证接收数据的一段可以正确解析数据,这就是应用层的作用,也是HTTP协议的作用之一。
HTTP协议的格式
HTTP协议分为HTTP请求和HTTP响应
HTTP请求:
说明:
- 第一部分为第一行,为请求行,请求行以空格分为三个区域,第一个区域叫请求方法,常见方法为POST,GET方法;第二个区域指名想要访问的资源(通常以路径的形式呈现)(网页也属于文件);第三个区域表示HTTP协议行的版本(常见1.0/1.1).
- 第二部分从第二行开始,一直到空前叫请求报头(Header),每一行都代表一个特定的含义,每一行格式都是name:value。
- 第三部分为空行,目的是为了将请求正文和请求行、请求报头分隔开(读到空格表示请求行和请求报头读完)。
- 第四部分问请求正文(Body可以为空,请求报头中的content-length表示正文大小)
HTTP响应:
说明:
- 第一部分为第一行,为响应行,也分为三个区域,用空格间隔,第一个区域表示协议版本;第二个区域表示状态码(200–表示请求正常处理完毕、404–表示无法处理请求等常见状态码);第三个区域表示状态码解释。
- 第二部分从第二行开始,一直到空前叫请求报头,每一行都代表一个特定的含义,每一行格式都是name:value。
- 第三部分为空行,目的是为了将请求正文和请求行、请求报头分隔开(读到空格表示请求行和请求报头读完)。
- 第四部分为正文(Body),空⾏后⾯的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有⼀个Content-Length属性来标识Body的⻓度。
常见状态码介绍:
实现一个简单的HTTP服务器
#include <sys/wait.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
void service(int sock, char* ip, int port)
{
char buf[10240];//用一个足够大的缓冲区一次性将数据读完
buf[0] = 0;
read(sock, buf, sizeof(buf));
const char* response = "HTTP/1.0 200 OK\n\n<html><head>hello world</head></html>\n";
write(sock, response, strlen(response));
}
int StartUp(int port)
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
{
perror("socket");
exit(2);
}
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_port = htons(port);
if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
{
perror("bind");
exit(3);
}
//设置为监听状态
if(listen(sock, 5) < 0)
{
perror("listen");
exit(4);
}
return sock;
}
// ./myHttp 0 9090
int main(int argc, char* argv[])
{
if(argc != 3)
{
printf("Usage: %s [ip] [port]\n", argv[0]);
exit(1);
}
int listen_sock = StartUp(atoi(argv[2]));
struct sockaddr_in peer;
int len = sizeof(peer);
socklen_t new_sock = -1;
daemon(0, 0);
while(1)
{
if((new_sock = accept(listen_sock, (struct sockaddr*)&peer, &len)) < 0)
{
printf("Connect faily\n");
continue;
}
char ipBuf[24] = {0};
inet_ntop(AF_INET, (struct sockaddr*)&peer, ipBuf, sizeof(ipBuf));
int p = ntohs(peer.sin_port);
printf("get a new connect: [%s %d]\n", ipBuf, p);
int id = fork();
if(id == 0)//child
{
close(listen_sock);
if(fork() > 0)
{
close(new_sock);
exit(0);
}
service(new_sock, ipBuf, p);
close(new_sock);
exit(0);
}
else if(id > 0)//father
{
close(new_sock);//因为父进程不通信
waitpid(id, NULL, 0);
continue;
}
else
{
perror("fork");
continue;
}
}
}
测试: centos 7
首先关闭防火墙(临时关闭):
//临时关闭
systemctl stop firewalld
//禁止开机启动
systemctl disable firewalld
Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
运行服务器
在浏览器上输入自己的ip地址:
结果如下: