A.使用 http: 或 https: 等协议方案名获取访问资源时要指定协议类型。
不区分字母大小写,最后附一个冒号(:)
b.登录信息(认证) 指定用户名和密码作为从服务器获取资源时必要的登录信息(身份 认证)。此项是可选项。
c。服务器地址 ,必须指定待访问的服务器地址。地址可以是类似 hackr.jp 这种 DNS
可解析的名称,或是 192,168.1.1 这类 IPV4 地址名,还可以是 [0:0:0:0:0:0:0:1]
这样用方括号括起来的 IPV6 地址名。
域名 等价于 ip地址
ip地址不能给用户提供任何有效信息
域名是字符串,可以给用户提供信息
d.服务器端口号 指定服务器连接的网络端口号。此项也是可选项,若用户省略则自动 使用默认端口号
e.带层次的文件路径 指定服务器上的文件路径来定位特指的资源。
f.查询字符串针对已指定的文件路径内的资源,可以使用查询字符串传入任意参数。此项可选。
g.片段标识符 使用片段标识符通常可标记出已获取资源中的子资源(文档内的某个 位置)。该项也为可选项.
模拟实习HTTP的服务端(接受浏览器请求并打印)
http_server.hpp
#pragma once
#include <stdio.h>
#include <unistd.h>//系统调用函数
#include <pthread.h>//线程调用函数
#include <sys/socket.h>//
#include <arpa/inet.h>//
#include <netinet/in.h>//
#include <iostream>//c++
class HttpSvr {
public:
HttpSvr() {
listen_sockfd_ = -1;
}
~HttpSvr() {
if (listen_sockfd_ > 0) {//析构
close(listen_sockfd_);
}
}
/*
* 初始化http服务的函数
* */
int OnInit() {
listen_sockfd_ = socket(AF_INET, SOCK_STREAM, 0);//创建套接字
if (listen_sockfd_ < 0) {
perror("socket");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8083);//8083转化成网络字节序
addr.sin_addr.s_addr = inet_addr("0.0.0.0");//监听任意一块网卡
int ret = bind(listen_sockfd_, (struct sockaddr*)&addr, sizeof(addr));//绑定套节字,与本地
if (ret < 0) {
perror("bind");
return -2;
}
ret = listen(listen_sockfd_, 5);//开始监听,允许监听最大连接数为5
if (ret < 0) {
perror("listen");
return -3;
}
return 0;
}
void StartSvr() {
while (1) {
struct sockaddr_in peer;//收集客户端信息
socklen_t peer_len = sizeof(peer);
int new_sockfd = accept(listen_sockfd_, (struct sockaddr*)&peer, &peer_len);//接受从客户端发送来的连接
if (new_sockfd < 0) {
continue;//接受失败重新接收
}
int* tmp = new int;//用临时变量存储,防止new_sockfd出了作用域销毁
*tmp = new_sockfd;
pthread_t tid;//线程标识符
int ret = pthread_create(&tid, NULL, WorkerStart, (void*)tmp);
if (ret < 0) {
close(new_sockfd);
delete tmp;
}
}
}
static void* WorkerStart(void* arg) {//线程工作函数
pthread_detach(pthread_self());//线程分离 自己回收自己退出状态信息
int new_sockfd = *((int*)arg);
delete (int*)arg; //可以释放了, 因为已经用临时变量保存了new_sockfd的值
while (1) {
char buf[4096] = { 0 };
ssize_t r_size = recv(new_sockfd, buf, sizeof(buf) - 1, 0);//接受传来的消息
if (r_size < 0) {
perror("recv");
continue;
}
else if (r_size == 0) {//返回值为0说明客户端已经主动与我们断开连接
close(new_sockfd);//关闭我们的套接字
break;
}
//normal
std::cout << "###########################begin###############" << " " << new_sockfd << std::endl;
//告诉我们客户端我们已经开始帮助他处理业务了(如果我们服务端不给客户局端返回东西,我们的浏览器会连续请求)
std::cout << buf;
std::cout << "###########################end###############" << " " << new_sockfd << std::endl;
//模拟构造响应内容
//响应首行
std::string content = "why not ?";
std::string line = "HTTP/1.1 200 OK\r\n";
std::string body = "Content-Type: text/html\r\n";
body += "Set-Cookie: linux77\r\n";
body += "Content-Length: 9\r\n\r\n";
//body += "Location: https://www.baidu.com/\r\n\r\n";
send(new_sockfd, line.c_str(), line.size(), 0);
send(new_sockfd, body.c_str(), body.size(), 0);
send(new_sockfd, content.c_str(), content.size(), 0);
if (new_sockfd < 0) {
printf("hello\n");
}
}
return NULL;
}
private:
//tcp的侦听套接字
int listen_sockfd_;
};
http_server.cpp
#include "http_server.hpp"
int main() {
HttpSvr hs;
int ret = hs.OnInit();
if (ret < 0) {
return 0;
}
hs.StartSvr();
return 0;
}
GET && POST
GET:
问服务端请求某些资源,还可以提交少量的数据,因为提交的内容并没有在
http协议的请求正文当中,而是在URL当中就是对应的查询字符串
POST:POST向服务端提交的数据在请求正文当中
(username:xxx && passwd:xxx)
面试题:POST方法和GET方法那个更安全
安全:数据在传输过程中被不法分子拿到
加密过的:安全
未加密:不安全
GET && POST不能决定数据是否加密
只能决定决定提交的数据在哪一个位置
GET :URL
POST:请求正文
POST方法比GET方法更私密(对于不太了解计算机的人)
协议版本
HTTP/0.9: HTTP 于 1990 年问世。那时的 HTTP 并没有作为正式的标准被建立。
现在的 HTTP 其实含有 HTTP1.0 之前版木的意思,因此被称为 HTTP/0.9。
HITP/1.0: HTTP正式作为标连被公布是在 1996 年的 5 月,版本被命名为 HTP/1.0,
记载于 REC1945。显说是初期标准,但该协议标准至今 仍被广泛使用在服务端
HTTP/1.1 1997公布的是目前主流的HTTP协议版本,当初的 准是 RFC2068,之后发布修订版
RFC2616 就是当前的最新本
HTTP/2.0: 新一代 HTTP/2.0 正在制订中,但要达到较高的使用覆盖率,仍需要假以时日。
请求头部
Host: 指定请求的服务器的域名和端口号
Accept: 指定客户端能够接收的内容类型。
Accepl-Language: 浏览器可接受的语言。
Accept-Charset; 浏览器可以接受的字符编码集。
Connection: 表示是否需要持久连接。(HTTP 1.1默认进行持久连接)
//之前都是你访问一次 我服务端 我服务端 还要为别人服务,返回你要的结果 连接就断开了
Content-Length: 请求的内容长度。
Content-Type: 请求的与实体对应的MIME信息。