Linux网络——HTTP

目录

一.应用层

二.认识URL

1.域名

2.urlencode和urldecode

三.HTTP协议格式 

1.请求格式http

2.响应格式

四.HTTP响应状态码

五.HTTP常见Header

六.简单的HTTP服务器

七.HTTP的方法

1.GET方法

2.POST方法


一.应用层

我们程序员写的一个个解决我们实际问题, 满足我们日常需求的网络程序, 都是在应用层.

我们上一次写的网络版本计算器就是一个应用层的网络程序。

我们约定了数据的读取,一端发送时构造的数据, 在另一端能够正确的进行解析, 就是ok的. 这种约定, 就是应用层协议。

在应用层我们只负责将数据怎么读取,和怎么构造数据,然后将构造好的数据交给应用层的协议层传输层,再由传输层何其一下的网络协议栈来帮我们完成数据在网络中发送,至于数据在这之间是怎么发送的,什么时候发送的,我们不知道,不清楚,也不关心。

二.认识URL

平时我们俗称的 "网址" 其实就是说的 URL.

1.域名

服务器地址可以是一个IP地址,但是IP地址是点分十进制的字符串,为了方便记忆就有了和IP地址一 一对应的域名。

例如:

  • 112.29.213.131 —— www.JD.com
  • 36.155.132.55   —— www.baidu.com

2.urlencode和urldecode

像 / ? : 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现.
比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义. 

转义的规则如下:
将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式,这个过程就是urlencode

 "+" 被转义成了 "%2B"。
urldecode就是urlencode的逆过程。

三.HTTP协议格式 

1.请求格式http

见一见http请求:

部分测试代码:

编写一个服务器,服务器多线程接受网络数据,使用浏览器在url栏框中输入服务端车程序的IP和端口,然后回车。此时浏览器就会构建一个http请求发送给我们的服务端程序,服务端程序直接将收到的数据直接以字符串的形式输出到终端。

    void serverIO(int fd){string message;char buff[102400];// 读取一个完整的http请求报文int n = recv(fd, buff, sizeof(buff), 0);message = buff;// 直接将该请求以字符串的形式输出cout << "得到一个HTTP请求" << endl;cout << message << endl;close(fd);}

得到的http请求:

2.响应格式

见一见http响应:

使用telnet 向百度模拟发送一个http请求,接受返回的http响应。

HTTP协议的格式大致有四部分组成:

  1. 首行:HTTP请求——[ 方法 ]+[ url ]+[ 版本 ];HTTP响应——[ 版本 ]+[ 状态码 ]+[ 描述 ];其中请求中url实际上就是服务器上的请求的资源路径。
  2. Header:请求/响应 的属性,冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分结束。例如:Content-Length:8899,标识 请求/响应 的有效载荷长度,有效载荷的长度是8899。
  3. 空行:用来分隔Header和Body。
  4. Body:就是有效载荷部分,空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有一个Content-Length属性来标识Body的长度;

四.HTTP响应状态码

状态码类别描述
1XX

lnformational(信息性状态码)

接收的请求正在处理

2XX

Success(成功状态码)

请求正常处理完毕

3XX

Redirection(重定向状态码)

需要进行附加操作以完成请求

4XX

Client Error(客户端错误状态码)

服务器无法处理请求

5XX

Server Error(服务器错误状态码)

服务器处理请求出错

说明:

Client Error:

  • 客户端连接的端口错了。
  • 客户端连接的域名或者IP地址错误。
  • 如果客户端使用了域名连接,域名可能指向了错误的服务器。
  • 当客户端发送了一个无效请求时,服务器可能会因为无法处理而返回 Client  Error。

lnformational:

  • 主要作用是告知客户端请求已经被接受 。

Redirection:

  • 是服务器在处理客户端请求时,为了保证流程的顺利进行而发出的一种信号。
  • 当客户端发送一个请求到服务器,服务器会根据需要将请求重定向到另一个URL。

 Success:

  • 表示客户端与服务器之间的通信已经成功完成,并且服务器已经处理了客户端的请求。

 Server Error:

  • 表示服务器在处理客户端请求时发生了错误。
  • 服务器遇到了一个未知的错误,无法完成请求的处理。
  • 服务器当前无法处理请求,因为过载或维护。

五.HTTP常见Header

Header是以K/V形式存储的字符串,主要是一些协议的属性说明等。

  1. Content-Type: 数据类型(text/html等)
  2. Content-Length: Body的长度
  3. Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
  4. User-Agent: 声明用户的操作系统和浏览器版本信息;
  5. referer: 当前页面是从哪个页面跳转过来的;
  6. location: 搭配3xx(重定向)状态码使用, 告诉客户端接下来要去哪里访问;
  7. Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;

 介绍Content-Type:表明此次http报文的body传输的是什么内容。

对于服务器上的每一种资源,都是以文件的形式存在的,文件都会有自己的类型,例如(网页文件).html,(音频文件).mp3,(图片).jpg/.png,(视频).mp4。

每一种文件类型,都会有自己对应的Content-Type类型:

  • text/html:HTML 文档
  • text/css:CSS 样式表
  • text/javascript:JavaScript 脚本
  • image/jpeg:JPEG 图像
  • image/png:PNG 图像
  • image/gif:GIF 图像

Content-Type 对照表

六.简单的HTTP服务器

编写一个服务器,多线程处理请求,对于请求的处理,解析一个http请求反序列化,根据http的请求的资源,构建响应并返回。

Sock.hpp

#pragma once
#include <iostream>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "Log.hpp"
#define TCP SOCK_STREAM
#define UDP SOCK_DGRAM
const static int backlog = 32;enum
{SOCK_ERR = 10,BING_ERR,LISTEN_ERR,CONNECT_ERR
};class Udp
{
public:Udp(int SOCK){_listensock = socket(AF_INET, SOCK, 0);if (_listensock == -1){Logmessage(Fatal, "socket err ,error code %d,%s", errno, strerror(errno));exit(SOCK_ERR);}}Udp(uint16_t port, int SOCK): _port(port){_listensock = socket(AF_INET, SOCK, 0);if (_listensock == -1){Logmessage(Fatal, "socket err ,error code %d,%s", errno, strerror(errno));exit(10);}}void Bind(){struct sockaddr_in host;host.sin_family = AF_INET;host.sin_port = htons(_port);host.sin_addr.s_addr = INADDR_ANY; // #define INADDR_ANY 0x00000000socklen_t hostlen = sizeof(host);int n = bind(_listensock, (struct sockaddr *)&host, hostlen);if (n == -1){Logmessage(Fatal, "bind err ,error code %d,%s", errno, strerror(errno));exit(BING_ERR);}}int FD(){return _listensock;}~Udp(){close(_listensock);}protected:int _listensock;uint16_t _port;
};class Tcp : public Udp
{
public:Tcp(uint16_t port): Udp(port, TCP){}Tcp(): Udp(TCP){}void Listen(){int n = listen(_listensock, backlog);if (n == -1){Logmessage(Fatal, "listen err ,error code %d,%s", errno, strerror(errno));exit(LISTEN_ERR);}}int Accept(string *clientip, uint16_t *clientport){struct sockaddr_in client;socklen_t clientlen;int sock = accept(_listensock, (struct sockaddr *)&client, &clientlen);if (sock < 0){Logmessage(Warning, "bind err ,error code %d,%s", errno, strerror(errno));}else{*clientip = inet_ntoa(client.sin_addr);*clientport = ntohs(client.sin_port);}return sock;}void Connect(string ip, uint16_t port){struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(port);server.sin_addr.s_addr = inet_addr(ip.c_str());socklen_t hostlen = sizeof(server);int n = connect(_listensock, (struct sockaddr *)&server, hostlen);if (n == -1){Logmessage(Fatal, "Connect err ,error code %d,%s", errno, strerror(errno));exit(CONNECT_ERR);}}~Tcp(){}
};

Server.hpp

#pragma once
#include <iostream>
#include <string>
#include <pthread.h>
#include <functional>
#include "Sock.hpp"using fun_t = std::function<string(string &)>;
class Httpserver;
struct Args
{Args(Httpserver *ser, string ip, uint16_t port, int fd): _ip(ip), _port(port), _pserver(ser), _fd(fd){}int _fd;uint16_t _port;string _ip;Httpserver *_pserver;
};class Httpserver
{
public:Httpserver(fun_t func, uint16_t port): _func(func){tcp = new Tcp(port);tcp->Bind();tcp->Listen();cout << "服务器创建成功" << endl;}void start(){while (1){string clientip;uint16_t clientport;cout << "start accept" << endl;int sock = tcp->Accept(&clientip, &clientport);cout << "get a new connect" << endl;// 多线程处理请求pthread_t t;Args *args = new Args(this, clientip, clientport, sock);pthread_create(&t, nullptr, ThreadRun, args);}}~Httpserver(){delete tcp;}private:static void *ThreadRun(void *args){pthread_detach(pthread_self());Args *ts = static_cast<Args *>(args);ts->_pserver->serverIO(ts->_fd);delete ts;return nullptr;}void serverIO(int fd){string message;char buff[102400];// 1.确信,读取一个完整的http请求报文int n = recv(fd, buff, sizeof(buff), 0);message = buff;string re = _func(message);send(fd, re.c_str(), re.length(), 0);close(fd);}private:Tcp *tcp;fun_t _func;
};

Server.cc

#include <sstream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/socket.h>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include "Server.hpp"
#include "util.hpp"const string wwwroot = "./html/3";
const string defaupath = "/index.html";class HttpRequest
{
public:HttpRequest(){}~HttpRequest() {}void Print(){cout << method_ << ":" << url_ << ":" << httpVersion_ << endl;for (auto &e : body_)cout << e << endl;cout << "suffix:" << suffix_ << endl;cout << "path:" << path_ << endl;}public:std::string method_;            // 请求方法std::string url_;               // 资源地址std::string httpVersion_;       // 协议版本std::vector<std::string> body_; // 报头std::string path_;   // 请求资源路径std::string suffix_; // 资源类型
};HttpRequest Deserialize(string &message)
{HttpRequest req;// 1.拿到请求行string oneline = HeadOneLine(message, SEP);// 2.解析请求行DisposeOneLine(oneline, &req.method_, &req.url_, &req.httpVersion_);// 3.解析反序列化报头while (!message.empty()){string mes = HeadOneLine(message, SEP);req.body_.push_back(mes);}// 4.设置请求资源路径 url:/a/b/cif (req.url_[req.url_.length() - 1] == '/'){req.path_ = wwwroot + defaupath; //./html/index.html}else{req.path_ = wwwroot + req.url_; //./html/a/b/c}// 5.设置请求资源类型auto pos = req.url_.find('.');if (pos == string::npos)req.suffix_ = ".html";elsereq.suffix_ = req.url_.substr(pos);return req;
}string Dispose(string &message)
{// 这里我们一定读取的是一个完整的报文// 一个网页会有很多的资源,每一个资源(网页,图片,视频),都需要一次http请求来得到// 所以我们需要知道,每次请求的资源是什么,即需要知道请求的url是什么,url的类型是什么// 反序列化请求HttpRequest req = Deserialize(message);req.Print();// 响应————最简单的一个响应// 4.有效载荷string body = Readfile(req.path_) + SEP;// 1.响应的状态行————"HTTP版本 状态码 状态描述\r\n"string request_head = string("HTTP/1.0 200 OK") + SEP;// 2.响应报头————Content-Length,Content-Typerequest_head += string("Content-Length: ") + to_string(body.length()) + SEP;request_head += GetContentType(req.suffix_) + SEP;// 3.空行request_head += SEP;// 整体的响应报文string responce = request_head + body;return responce;
}void daemonize()
{// 1.忽略SIGPIPE信号signal(SIGPIPE, SIG_IGN);// 2.更改进程的工作目录// chdir();// 3.让自己不要成为进程组组长if (fork() > 0)exit(0);// 4.设置自己是一个独立的会话setsid();// 5.重定向0,1,2int fd = 0;if (fd = open("dev/null", O_RDWR) != -1){dup2(fd, STDIN_FILENO);dup2(fd, STDOUT_FILENO);dup2(fd, STDERR_FILENO);// 6.关闭掉不需要的fdif (fd > STDERR_FILENO){close(fd);}}
}int main(int argc, char *argv[])
{daemonize();uint16_t port = atoi(argv[1]);Httpserver httpser(Dispose, port);httpser.start();return 0;
}

Util.hpp

#pragma once
#include <iostream>
#include <unistd.h>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>#define SEP "\r\n"
using namespace std;string Readfile(const string path)
{// 1. 获取文件本身的大小string fileContent;struct stat st;int n = stat(path.c_str(), &st);if (n < 0)return "";int size = st.st_size;// 2. 调整string的空间fileContent.resize(size);// 3. 读取int fd = open(path.c_str(), O_RDONLY);if (fd < 0)return "";read(fd, (char *)fileContent.c_str(), size);close(fd);return fileContent;
}string HeadOneLine(string &message, const string &sep)
{auto pos = message.find(sep, 0);if (pos == string::npos)return "";string oneline = message.substr(0, pos);message.erase(0, pos + sep.size());return oneline;
}void DisposeOneLine(const string &oneline, string *method, string *url, string *httpVersion)
{stringstream line(oneline);line >> *method >> *url >> *httpVersion;
}string GetContentType(const string &suffix)
{std::string content_type = "Content-Type: ";if (suffix == ".html" || suffix == ".htm")content_type + "text/html";else if (suffix == ".css")content_type += "text/css";else if (suffix == ".js")content_type += "application/x-javascript";else if (suffix == ".png")content_type += "image/png";else if (suffix == ".jpg")content_type += "image/jpeg";else{}return content_type;
}

效果展示:

七.HTTP的方法

HTTP的方法有很多但是最常用的只有两个:GET,POST。

1.GET方法

我们要促使浏览器使用不同的方法进行资源请求,提交,要使用html的表单。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>CSDN</title>
</head><body><h1>test</h1><form action="/a/b/c.exe" method="get">姓名: <input type="text" name="myname" value=""><br />密码: <input type="password" name="mypasswd"><br /><input type="submit" value="提交"><br /></form></body></html>

尝试提交数据:

2.POST方法

再次尝试提交数据:

 区别:

  1. GET能获取一个静态网页,GET也能提交参数,通过URL的方式提交参数。
  2. POST请求,提交的参数的时候,是通过正文的部分提交的参数。
  3. GET方法提交参数,不私密(没有不安全的说法),安全对HTTP来说本身就没有保障。
  4. POST提交参数比较私密一些。
  5. 由于GET使用url提交参数,所以大小一般会受限。
  6. POST使用正文提交参数,正文理论上可以非常大。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/150728.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

虾皮台湾站点什么好卖

在如今的电商时代&#xff0c;越来越多的人选择通过网购来满足购物需求。而中国台湾地区作为一个充满机遇的市场&#xff0c;吸引了许多商家的目光。虾皮作为台湾地区最大的电商平台之一&#xff0c;为卖家提供了丰富的销售机会。但是&#xff0c;卖家们在选择什么产品来销售时…

Error: Cannot find module ‘node:util‘

安装cnpm后报错如图&#xff1a; 原因&#xff1a;node版本是14.19.3&#xff0c;cnpm版本不匹配&#xff0c;卸载掉重新安装对应版本。 卸载cnpm命令&#xff1a; npm uninstall -g cnpm --registryhttps://registry.npm.taobao.org 安装对应版本命令&#xff1a; npm ins…

OpenCV快速入门:像素操作和图像变换

文章目录 前言1. 像素操作1.1 像素统计1.2 两个图像之间的操作1.2.1 图像加法操作1.2.3 图像加权混合 1.3 二值化1.4 LUT&#xff08;查找表&#xff09;1.4.1 查找表原理1.4.2 代码演示 2 图像变换2.1 旋转操作2.1.1 旋转的基本原理2.1.2 代码实现 2.2 缩放操作2.3 平移操作2.…

这两个让你直呼卧槽的软件,超级实用

不知道大家有没有碰到这种情况呢&#xff1f;在手机上解压文件解压不了&#xff0c;还得去电脑上下载之后解压&#xff0c;特别麻烦 为了解决这一问题&#xff0c;所以今天给大家准备 两款 解压缩 神器&#xff0c;让大家解的越来越熟练。 解压精灵 解压精灵这是一款解压缩并且…

《微信小程序开发从入门到实战》学习二十

3.3 开发创建投票页面 3.3.8 使用icon图标文件 原来已经实现了投票选项的增加和修改功能&#xff0c;现在还差删除。现在为每一个选项增加删除按钮&#xff0c;可以以通过icon图标组件实现。 icon常用属性如下&#xff1a; type icon的类型&#xff0c;有success、s…

我们常说的网络资产,具体是如何定义的?

文章目录 什么叫网络资产&#xff1f;官方定义的网络资产网络资产数字化定义推荐阅读 什么叫网络资产&#xff1f; 通过百度查询搜索什么叫网络资产&#xff1f;大体上都将网络资产归类为计算机网络中的各类设备。 基本上会定义网络传输通信架构中用到的主机、网络设备、防火…

如何在本地搭建Oracle数据库实现公网环境下通过PLSQL工具进行远程访问

文章目录 前言1. 数据库搭建2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射 3. 公网远程访问4. 配置固定TCP端口地址4.1 保留一个固定的公网TCP端口地址4.2 配置固定公网TCP端口地址4.3 测试使用固定TCP端口地址远程Oracle 前言 Oracle&#xff0c;是甲骨文公司的一款关系…

小鸟飞呀飞

欢迎来到程序小院 小鸟飞呀飞 玩法&#xff1a;鼠标控制小鸟飞翔的方向&#xff0c;点击鼠标左键上升&#xff0c;不要让小鸟掉落&#xff0c;从管道中经过&#xff0c;快去飞呀飞哦^^。开始游戏https://www.ormcc.com/play/gameStart/204 html <canvas width"288&quo…

工业4.0时代,烤漆房控制柜如何远程监控?

烤漆房控制柜远程监控方案 一、现状 烤漆房是汽车、机械、家具等工业领域广泛应用的设备&#xff0c;主要用于产品的表面涂装。传统的烤漆房控制柜采用本地控制方式&#xff0c;操作人员在现场进行参数设置和设备控制。这种控制方式需要操作人员需要具备一定的专业知识&#x…

2023-2024华为ICT大赛-计算赛道-广东省省赛初赛-高职组-部分赛题分析【2023.11.18】

2023-2024华为ICT大赛 计算赛道 广东省 省赛 初赛 高职组 部分赛题 分析【2023.11.18】 文章目录 单选题tpcds模式中存在表customer&#xff0c;不能成功删除tpcds模式是&#xff08; &#xff09;以下哪个函数将圆转换成矩形&#xff08; &#xff09;下列哪个选项表示依赖该D…

新版Testwell CTC++带来哪些新变化?

Testwell CTC在版本10中引入了新的工具ctcreport来直接从符号和数据文件生成HTML报告。详细的特性描述可以在测试井CTC帮助中找到。在本文档中&#xff0c;描述了与前一代报告相比的改进和变化。 Adaptable Layout可调整布局 您可以选择一个适合于项目结构的布局。布局决定了报…

three.js实现管道漫游

先看效果&#xff1a; <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red"></div><div class"box-right"><pre s…

xaml自动格式化:各个属性分行放置

快捷键&#xff1a;CtrlKD 设置自己需要的属性&#xff1a;工具->选项->文本编辑器->XAML->Formatting 效果如下&#xff1a;

深度学习YOLO图像视频足球和人体检测 - python opencv 计算机竞赛

文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络4 Yolov5算法5 数据集6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习YOLO图像视频足球和人体检测 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非…

【用unity实现100个游戏之16】Unity程序化生成随机2D地牢游戏1(附项目源码)

文章目录 先看看最终效果前言随机游走算法使用随机游走算法添加地板瓦片1. 新增TilemapVisualizer&#xff0c;用于可视化地图2. 瓦片素材 不运行执行程序化生成地牢方法1. 先简单重构代码2. 新增Editor脚本RandomDungeonGeneratorEditor 将参数保存到可编辑脚本对象&#xff0…

Java-final

【1】修饰变量&#xff1b; 1.public class Test { 2. //这是一个main方法&#xff0c;是程序的入口&#xff1a; 3. public static void main(String[] args) { 4. //第1种情况&#xff1a; 5. //final修饰一个变量&#xff0c;变量的值不可以改变&#…

【考研数学】正交变换后如果不是标准型怎么办?| 关于二次型标准化的一些思考

文章目录 引言一、回顾二次型的定义是什么&#xff1f;什么叫标准二次型&#xff1f;怎么化为标准型&#xff1f; 二、思考写在最后 引言 前阵子做了下 20 年真题&#xff0c;问题大大的&#xff0c;现在订正到矩阵的第一个大题&#xff0c;是关于二次型正交变换的。和常规不同…

当代职场人做分析,当然要用大数据分析工具

不管是从效率、分析的可用性以及灵活性来看&#xff0c;用大数据分析工具都还板上钉钉的。毕竟大数据分析工具集齐了大数据时代数据分析工具应具备的特点优势。 1、对接ERP&#xff0c;立得100BI报表 点击对接金蝶、用友ERP后&#xff0c;BI系统立即即可取数分析&#xff0c;…

控制实体小车cartographer建图

cartographer建图 跑通官方例程 下载官方bag https://storage.googleapis.com/cartographer-public-data/bags/backpack_2d/cartographer_paper_deutsches_museum.bag运行bag roslaunch cartographer_ros demo_backpack_2d.launch bag_filename:${HOME}/workspace/carto_ws…

Swift-day 2

1、数据绑定&#xff0c;改变标题 State private var zoomed: Bool false 属性包装器包装的变量self.title 单向绑定 self.$textInput 双向绑定 传的是数据结构 self.title self.textInput 赋值是String self._titletitle //绑定类型加下划线2、数据绑定&#xff0c;传递结构…