1.HTTP是什么
HTTP即HypertText TranSport Protocol(超文本传输协议),建立在TCP和IP协议之上。
1.1 HTTP/0.9 - 单线协议
TTP的初始版本没有版本号; 它后来被称为0.9来区分它和更高版本。HTTP / 0.9非常简单:请求由一行代码组成,并从唯一可能的方法开始,GET然后是资源路径(不是URL,因为连接到服务器后不需要协议,服务器和端口)。
1.2 HTTP/1.0 - 构建扩展性
HTTP/0.9的功能非常有限,所以HTTP/1.0多了以下特性:
- 版本信息在每个请求中发送。
- 状态码行也在响应开始时发送,允许浏览器自己了解请求的成功或失败并调整其行为。
- 已经引入了HTTP标头的概念,包括请求和响应,允许传输元数据并使协议非常灵活和可扩展。
- 在新的HTTP标题的帮助下,增加了传输其他文档而不是纯HTML文件的功能。
1.2 HTTP/1.1 - 标准化协议
HTTP/1.1在1.0上做出了很多改进的地方:
- 连接可以重复使用,节省重新打开多次的时间,以显示嵌入到检索到的单个原始文档中的资源。
- 流水线已添加,允许在第一个请求的答案完全传输之前发送第二个请求,从而降低通信延迟。
- 分块响应现在也支持。
- 额外的缓存控制机制已经被引入。
- 内容协商(包括语言,编码或类型)已经引入,并允许客户和服务器就最适合交换的内容达成一致。
2.HTTP协议格式
2.1 请求格式
可以看到,请求格式分为首行,头部,正文。
- 首行:方法+URL+状态码。
- 头部:请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分结束。
- 正文:空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有一个 Content-Length属性来标识Body的长度。
2.2 响应格式
和请求格式一样,响应格式也分为首行+头部+正文。
- 首行: [版本号] + [状态码] + [状态码解释] 。
- 头部: 请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分结束。
- 正文: 空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有一个 Content-Length属性来标识Body的长度; 如果服务器返回了一个html页面, 那么html页面内容就是在 body中。
2.3常见的头部信息
Content-Type: 数据类型(text/html等) 。
Content-Length: Body的长度。
Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上。
User-Agent: 声明用户的操作系统和浏览器版本信息。
referer: 当前页面是从哪个页面跳转过来的。
location: 搭配3xx状态码使用, 告诉客户端接下来要去哪里访问。
Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能。
3.URL是什么
URL — Uniform Resource Location统一资源定位符
例如这个url:
https://cloud.tencent.com/developer/section/1189853
https是协议,cloud.tencent.com是域名,后面的是查询路径,
再来看下面这个url:
注意?后面的内容,是提供给 Web 服务器的额外参数。这些参数是用&符号分隔的键/值对列表。在将资源返回给用户之前,Web 服务器可以使用这些参数来执行额外的工作。每个 Web 服务器都有自己的参数规则,知道特定 Web 服务器如何处理参数的唯一可靠方法是询问 Web 服务器所有者。
4.简单的http服务器实现
#include<iostream>
#include<string>
#include<unistd.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/types.h>
#include <arpa/inet.h>
#define CHECK_RET(q) if((q) == false){return -1;}
class Tcpsocket{
public:
Tcpsocket():_sockfd(-1){}
~Tcpsocket(){Close();}
bool Sock(){
_sockfd = socket(AF_INET,SOCK_STREAM,0);
if(_sockfd < 0){
std::cerr << "create error\n";
return false;
}
return true;
}
bool Bind(const std::string& ip,uint16_t port){
struct sockaddr_in server_socket;
server_socket.sin_family = AF_INET;
server_socket.sin_port = htons(port);
server_socket.sin_addr.s_addr = inet_addr(&ip[0]);
int ret = bind(_sockfd,(struct sockaddr*)& server_socket,sizeof(sockaddr_in));
if(ret < 0){
std::cerr << "bind error\n";
return false;
}
return true;
}
bool Listen(int BACKLOGS = 5){
int ret = listen(_sockfd,BACKLOGS);
if(ret < 0){
std::cerr << "listen error\n";
return false;
}
return true;
}
void SetFd(int fd){
_sockfd = fd;
}
bool Accept(Tcpsocket& cli_sock){
struct sockaddr_in addr;
socklen_t len = sizeof(struct sockaddr_in);
int fd = accept(_sockfd,(struct sockaddr*)&addr,&len);
if(fd < 0){
std::cerr << "accept error\n";
return false;
}
cli_sock.SetFd(fd);
return true;
}
bool Connect(std::string& ip,uint16_t port){
int ret;
struct sockaddr_in client_socket;
client_socket.sin_family = AF_INET;
client_socket.sin_port = htons(port);
client_socket.sin_addr.s_addr = inet_addr(&ip[0]);
socklen_t len = sizeof(struct sockaddr_in);
ret = connect(_sockfd,(struct sockaddr*)& client_socket,len);
if(ret < 0) {
std::cerr << "connect error\n";
return false;
}
return true;
}
bool Send(std::string buff){
int ret = send(_sockfd,&buff[0],buff.size(),0);
if(ret < 0){
std::cerr << "send error\n";
return false;
}
return true;
}
bool Recv(std::string buff){
char tmp[4096] = {0};
int ret = recv(_sockfd,tmp,4096,0);
if(ret < 0){
std::cerr << "recv error\n";
return false;
}else if(ret == 0){ //recv返回值为0表示连接已断开
std::cerr << "peer shutdown\n";
return false;
}
buff.assign(tmp,ret);
return true;
}
bool Close(){
if(_sockfd >= 0){
close(_sockfd);
_sockfd = -1;
}
}
private:
int _sockfd;
};
© 2020 GitHub, Inc.
#include"tcpsocket.hpp"
#include<sstream>
int main(int argc, char* argv[])
{
Tcpsocket sock;
CHECK_RET(sock.Sock());
CHECK_RET(sock.Bind("0.0.0.0",9000));
CHECK_RET(sock.Listen());
while(1)
{
Tcpsocket clisock;
if(sock.Accept(clisock) == false){
continue;
}
std::string buff;
clisock.Recv(buff);
std::cout << "req:[" << buff << "]\n";
std::string body = "<html><body><h1>hello</h1></body></html>";
std::string first = "HTTP/1.1 200 OK\r\n";
std::string head;
std::stringstream ss;
ss << "Content-Length: " << body.size() << "\r\n";
head = ss.str();
std::string blank = "\r\n";
clisock.Send(first);
clisock.Send(head);
clisock.Send(blank);
clisock.Send(body);
clisock.Close();
}
sock.Close();
return 0;
}
来源:CSDN
作者:爱喝可乐的loser
链接:https://blog.csdn.net/weixin_42549259/article/details/104463765