Linux网络——HTTP

这篇具有很好参考价值的文章主要介绍了Linux网络——HTTP。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一.应用层

二.认识URL

1.域名

2.urlencode和urldecode

三.HTTP协议格式 

1.请求格式http

2.响应格式

四.HTTP响应状态码

五.HTTP常见Header

六.简单的HTTP服务器

七.HTTP的方法

1.GET方法

2.POST方法


Linux网络——HTTP,网络编程,网络

一.应用层

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

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

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

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

二.认识URL

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

Linux网络——HTTP,网络编程,网络

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

Linux网络——HTTP,网络编程,网络

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

三.HTTP协议格式 

1.请求格式http

Linux网络——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请求:

Linux网络——HTTP,网络编程,网络

2.响应格式

Linux网络——HTTP,网络编程,网络

见一见http响应:

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

Linux网络——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 0x00000000
        socklen_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/c
    if (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";
    else
        req.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-Type
    request_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,2
    int fd = 0;
    if (fd = open("dev/null", O_RDWR) != -1)
    {
        dup2(fd, STDIN_FILENO);
        dup2(fd, STDOUT_FILENO);
        dup2(fd, STDERR_FILENO);
        // 6.关闭掉不需要的fd
        if (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;
}

效果展示:

Linux网络——HTTP,网络编程,网络

七.HTTP的方法

Linux网络——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>

Linux网络——HTTP,网络编程,网络

尝试提交数据:

Linux网络——HTTP,网络编程,网络

Linux网络——HTTP,网络编程,网络

2.POST方法

Linux网络——HTTP,网络编程,网络

再次尝试提交数据:

Linux网络——HTTP,网络编程,网络

 区别:文章来源地址https://www.toymoban.com/news/detail-751559.html

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

到了这里,关于Linux网络——HTTP的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • ℰ悟透Qt—Http网络编程

    ℰ悟透Qt—Http网络编程

    网络访问 API 建立在一个 QNetworkAccessManager 对象之上,该对象保存了发送请求所需的公共配置和设置。它包含代理和缓存配置,以及与此类问题相关的信号和可用于监视网络操作进度的回复信号。整个 Qt 应用程序只需要一个 QNetworkAccessManager 实例。由于 QNetworkAccessManager 基于

    2024年02月11日
    浏览(14)
  • Python中的网络编程Socket与HTTP协议的实践【第158篇—网络编程】

    Python中的网络编程Socket与HTTP协议的实践【第158篇—网络编程】

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 在当今互联网时代,网络编程是程序员不可或缺的一项技能。Python作为一种高级编程语言,提供了丰富的网络编程库,使得开发者能够轻松地

    2024年04月09日
    浏览(11)
  • 网络套接字编程(三)(HTTP)

    网络套接字编程(三)(HTTP)

    gitee仓库:https://gitee.com/WangZihao64/linux/tree/master/CalTcp 协议 是一种“约定”,这种约定是双方都知道的。有了一致的约定,双方才能够正常地进行通信。协议在网络的第一篇博客中也提到过,协议是双方进行通信的基础,在网络通信中存在着各种协议,有了这些协议,网络的通

    2024年02月16日
    浏览(7)
  • Go语言的网络编程与HTTP服务

    Go语言(Golang)是Google开发的一种静态类型、垃圾回收、并发简单的编程语言。Go语言的设计目标是让程序员更容易编写并发程序,并在多核处理器上充分发挥性能。Go语言的网络编程和HTTP服务是其核心功能之一,可以轻松地构建高性能、可扩展的网络应用程序。 在本文中,我们

    2024年02月19日
    浏览(43)
  • Android网络编程,HTTP请求和Json解析

    以下代码模拟了点击按钮请求百度的网页源码: 其中需要注意的是Android在API27之后不再支持明文访问HTTP,需要在manifest文件中配置属性允许使用明文访问, 并且Url需要使用https layout.xml 字节流转换字符串工具类: 主类.java: 配置manifest.xml文件: 将上述代码中的webview相关内容

    2023年04月09日
    浏览(13)
  • 【Java网络编程】HTTP超文本传输协议

    【Java网络编程】HTTP超文本传输协议

        HTTP 全称为 Hyper Text Transfer Protocol 超文本传输协议,它是基于 TCP 传输协议构建的应用层协议,作为支撑万维网 www 的核心协议,为了保证其效率及处理大量事务的能力,因此在设计时, HTTP 被制定成为一种无状态协议,也就是说: HTTP 本身不会对发送过的请求和相应的通

    2024年04月09日
    浏览(10)
  • 【网络编程】一文详解http协议(超文本传输协议)

    【网络编程】一文详解http协议(超文本传输协议)

    需要云服务器等云产品来学习Linux的同学可以移步/--腾讯云--/--阿里云--/--华为云--/官网,轻量型云服务器低至112元/年,新用户首次下单享超低折扣。    目录 一、http协议 1、http协议的介绍 2、URL的组成 3、urlencode和urldecode 二、http的请求方法、状态码及状态码描述、常见的响

    2024年02月06日
    浏览(16)
  • python基于http的网络通信和网站端口暴露;Python网络编程之HTTP协议的python应用

    HTTP(Hypertext Transfer Protocol)即超文本传输协议,是Web应用程序使用的协议,在Web浏览器和Web服务器之间传递HTML页面和数据。HTTP是基于TCP/IP协议来传输数据的,是一种无状态的协议。 关键特点: 支持客户/服务器模式:Web浏览器作为HTTP客户端通过URL向HTTP服务器发送HTTP请求,

    2024年02月04日
    浏览(14)
  • 学习网络编程No.8【应用层协议之HTTP】

    学习网络编程No.8【应用层协议之HTTP】

    北京时间:2023/10/9/13:03,一晃好多天过去了,9月14号的文章终于在昨天发出去了,也是许久没有更文了,国庆放假期间由于各种原因,在王者峡谷和铲子世界遨游的不亦乐乎,有待改善!目前面临挑战艰巨,问题很多,在这个空窗期我们需要有一股强大的支撑作为动力,毕竟

    2024年02月08日
    浏览(12)
  • Java 网络编程 —— 创建非阻塞的 HTTP 服务器

    HTTP 客户程序必须先发出一个 HTTP 请求,然后才能接收到来自 HTTP 服器的响应,浏览器就是最常见的 HTTP 客户程序。HTTP 客户程序和 HTTP 服务器分别由不同的软件开发商提供,它们都可以用任意的编程语言编写。HTTP 严格规定了 HTTP 请求和 HTTP 响应的数据格式,只要 HTTP 服务器

    2024年02月06日
    浏览(13)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包