【linux】网络基础 ---- 应用层

1. 再谈 "协议"

协议是一种 "约定",在读写数据时, 都是按 "字符串" 的方式来发送接收的.

但是这里我们会遇到一些问题:

如何确保从网上读取的数据是否是完整的,区分缓冲区中的由不同客户端发来的数据

2. 网络版计算器

举例:我们需要实现一个服务器版的加法器. 我们需要客户端把要计算的两个加数发过去, 然后由服务器进行计算, 最后再把结果返回给客户端

约定方案一:

客户端发送一个形如"1+1"的字符串;

这个字符串中有两个操作数, 都是整形;

两个数字之间会有一个字符是运算符, 运算符只能是 + ;

数字和运算符之间没有空格;

结果:不可取,无法判断从网上读取的数据是否是完整的

约定方案二:

定义结构体来表示我们需要交互的信息;

发送数据时将这个结构体按照一个规则转换成字符串(这个过程叫做 "序列化"), 接收到数据的时候再按照相同的规则把字符串转化回结构体;(这个过程叫做“反序列化”)

自定义序列化,反序列化

#include<iostream>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string>
#include<memory>
#include<unistd.h>
using namespace std;
#include"head.hpp"
class sock
{
public:
     sock(uint16_t port = 8080)
    :_port(port)
    {}
    void Init()
    {
        fd = socket(AF_INET,SOCK_STREAM,0);
        if(fd < 0)
        {
            cout << "socket fail" << endl;
            exit(1);
        }
    }
    void Bind()
    {
        sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(_port);
        addr.sin_addr.s_addr = inet_addr("0.0.0.0");
        socklen_t len = sizeof(addr);
        int n = bind(fd,(struct sockaddr*)&addr,len);
        if(n < 0)
        {
            cout << "bind fail" << endl;
            exit(2);
        }
    }
    void Listen()
    {
        int n = listen(fd,0);
        if(n < 0)
        {
            cout << "listen fail" << endl;
            exit(3);
        }
    }
    void Accept(int &client_fd)
    {
        sockaddr_in addr;
        socklen_t len = sizeof(addr);
        client_fd = accept(fd,(struct sockaddr*)&addr,&len);
        if(client_fd < 0)
        {
            cout << "accept fail" << endl;
        }
        else
        {
            cout << "get a new link ..." << endl;
        }
    }
    int  Connect(const uint16_t& port,const string &s)
    {
        sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr = inet_addr(s.c_str());
        socklen_t len = sizeof(addr);
        int n = connect(fd,(struct sockaddr*)&addr,len);
        if(n < 0)
        {
            cout << "connect fail" << endl;
            exit(4);
        }
        return fd;
    }
private:
    int fd;
    uint16_t _port;
};
#include<string>
string package(const string &content)
{
     //len\ncontent\n
     int n = content.size();
     string s = to_string(n);
     s += '\n';
     s += content;
     s += '\n';
     return s;
}
string prase(string &package)
{
    //len  \n  content  \n
    size_t pos = package.find('\n');
    if(pos == string :: npos)
    {
        return nullptr;
    }
    int len_package = package.size();
    string l = package.substr(0,pos);
    int len = stoi(package.substr(0,pos));
    if(l.size() + 2 + len > len_package)
    {
        return nullptr;
    }
    string s;
    s = package.substr(pos + 1,len);
    package.erase(0,l.size() + 2 + len);
    return s;

}
struct protocol_client
{
    protocol_client(int x = 0,int y = 0,char op = '+')
    :_x(x)
    ,_y(y)
    ,_op(op)
    {}
    string serialize()
    {
        // _x _op _y
        string s;
        s += to_string(_x);
        s += " ";
        s += _op;
        s += " ";
        s += to_string(_y);
        return s;
    }
    void deserialize(const string &s)
    {
        int left = s.find(' ');
        if(left == string :: npos)
        {
            cout << "protocol_client : find fail" << endl;
        }
        int right = s.rfind(' ');
        if(right == string :: npos)
        {
            cout << "protocol_client : find fail" << endl;
        }
        if(left + 2 != right)
        {
            cout << "protocol_client : deserialize fail" << endl;
            return ;
        }
        _x = stoi(s.substr(0,left));
        _y = stoi(s.substr(right + 1));
        _op = s[left + 1];
    }


    int _x;
    int _y;
    char _op;
};
struct protocol_server
{
    protocol_server(int result = 0,int code = 0)
    :_code(code)
    , _result(result)
    {}
    string serialize()
    {
        //_result _code
        string s;
        s += to_string(_result);
        s += " ";
        s += to_string(_code);
        return s;
    }
    void deserialize(const string &s)
    {
        size_t pos = s.find(" ");
        if(pos == string :: npos)
        {
            cout << "protocol_client : find fail" << endl;
        }
        _result = stoi(s.substr(0,pos));
        _code = stoi(s.substr(pos + 1));
    }

int _code;
int _result;
};
#include"server.hpp"
int main()
{
     
    unique_ptr<server> sv(new server());
    sv->start();
    sv->run();
    return 0;
}
#include "sock.hpp"
#include"protocol.hpp"
class server
{
public:
     server()
     {}
     void start()
     {
        svr.Init();
        svr.Bind();
        svr.Listen();
     }
     void run()
     {
        int client_fd;
        svr.Accept(client_fd);
        string e;
        while(true)
        {
            //读端
            char buff[1024];
            ssize_t n = read(client_fd, buff, sizeof(buff));
            if (n < 0)
            {
                cout << "server : read fail" << endl;
            }
            buff[n] = 0;
            
            e += buff;
            string s = prase(e);
            protocol_client sv;
            sv.deserialize(s);
            
            //计算
            int result,code = 0;
            switch(sv._op)
            {
                case '+':
                result = sv._x + sv._y;
                break;
                case '-':
                result = sv._x - sv._y;
                break;
                case '*':
                result = sv._x * sv._y;
                break;
                case '/':
                if(sv._y == 0)
                {
                    code = 1;
                }
                else
                {
                    result = sv._x / sv._y;
                }
                break;
                default:
                code = 2;
            }

            protocol_server ss(result,code);
            s = ss.serialize();
            s = package(s);

            //写端
            
            n = write(client_fd,s.c_str(),s.size());
            if(n < 0)
            {
                cout << "server : write fail" << endl;
            }
        }
        
     }
private: 
    sock svr;
};
#include"sock.hpp"
#include"protocol.hpp"
void usage()
{
    cout << "x + y = ? " << endl;
}

int main()
{
    uint16_t port = 8080;
    sock client;
    client.Init();
    int fd = client.Connect(port,"1.94.49.66");
    string e;
    while(true)
    {
        usage();
        int x,y;
        char op;
        //写端
        cout << "please enter: x >   ";
        cin >> x;
        cout << "please enter: op >   ";
        cin >> op;
        cout << "please enter: y >   ";
        cin >> y;
        protocol_client sv(x,y,op);
        string s = sv.serialize();
        s = package(s);
        
        ssize_t n = write(fd,s.c_str(),s.size());
        if(n < 0)
        {
            cout << "client : write fail" << endl;
        }
        

        //读端
        char buff[1024];
        n = read(fd,buff,sizeof(buff));
        if(n < 0)
        {
            cout << "client : read fail" << endl;
        }
        buff[n] = 0;
        e += buff;
        s = prase(e);  
        protocol_server ss;
        ss.deserialize(s);
        
        cout << "result : " << ss._result << "    code : " << ss._code << endl;

        cout << "-------------------------------------------------------------" << endl << endl;
    }
    
    return 0;
}

 json类

#include<jsoncpp/json/json.h>
int main()
{
    Json::Value root;
    root["x"] = 100;
    root["y"] = 200;
    root["op"] = '+';
    root["dect"] = "this is a + oper";
    Json::FastWriter w;
    string res = w.write(root);
    cout << res << endl;
    return 0;
}
Json::Value v;
Json::Reader r;
r.parse(res,v);
int x = v["x"].asInt();
int y = v["y"].asInt();
char op = v["op"].asInt();
string dect = v["dect"].asString();

3. HTTP协议

(一)认识 HTTP协议

应用层协议是我们程序员自己定的,但实际上, 已经有一些现成的, 又非常好用的应用层协议, 供我们直接参考使用,如 HTTP(超文本传输协议) 就是其中之一.

(二)认识URL

平时我们说 "网址" 就是URL

注意:

  1. 像网站这种,一般默认会添加协议方案名,且协议方案名对应唯一一个端口号,所以即使不写端口号,也没关系(如:http 对应端口号 80,https 对应端口号 443)
  2. web根目录不一定是linux系统下的根目录,具体指什么,完全由服务器那边解释

(三)urlencode(编码) 和 urldecode(解码)

像 / ? : 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现

所以,如果某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义.

转义的规则如下(这个过程叫编码):

将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式

编码解码工具:

URL 编码解码 - Codeeeee 在线小工具

4. HTTP协议格式

注意:

  1. 上图对应格式是打印出来的格式,实际上,发送到网络上的是整个字符串,是连在一起的
  2. http也是一种协议,它也需要将数据序列化,反序列化

代码

5. HTTP的方法

其中最常用的就是 GET方法 和 POST方法

注意:

  1. GET 方法 和 POST 方法都可以传参
  2. GET 方法的参数是在 url 内的,通过 url 提交的,POST 方法的参数是在正文内
  3. POST 方法 比 GET 方法更加私密

GET 方法:

POST 方法:

6. HTTP的状态码

最常见的状态码, 比如 200(OK), 404(Not Found,一般是客户端要访问的文件不存在), 403(Forbidden), 302(Redirect, 重定向), 504(Bad Gateway)

注意:

  1. 3XX代表的重定向有两种:一种是临时移动,另一种是长期移动
  2. 长期移动:一旦设置了永久重定向,所有后续对原始URL的请求都应该被自动转发到新的URL,而且这个重定向是长期有效的;临时移动:表明资源的移动是暂时的。 客户端在接收到临时重定向响应后,会临时使用新的URL,但在将来的某个时间点,对原始URL的请求可能会恢复为直接访问原始资源,而不是被重定向

HTTP常见Header

Content-Type: 数据类型(text/html等)

Content-Length: Body的长度

Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;

User-Agent: 声明用户的操作系统和浏览器版本信息;

referer: 当前页面是从哪个页面跳转过来的;

location: 搭配3xx状态码使用, 告诉客户端接下来要去哪里访问;

Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能

注意:

  1. Content-Type : 指明访问的路径是什么类型(如:.html : 网页 ; .jpg :jpg格式的图片 ;.png : png格式的图片 ...... )
  2. Cookie : Cookie文件可能是内存级的(储存在内存里),也可能是文件级的(储存在磁盘里)

  1. cookie文件的内容保存多久,一般是由浏览器决定的,如果内容没有了,则下一次访问对应服务器,仍要进行验证
  2. http协议默认是无状态的
  3. http对登入用户的会话保持功能

7. 长连接和短连接

  1. 即使是一个网页,也可能包含很多元素,每一个元素,都要进行一次http请求,即建立一个tcp连接,就会发生多个请求和响应,这就是长连接
  2. 只有一次请求和响应,连接就断开的,就是短连接

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Zookeeper运维秘籍:四字命令基础、详解及业务应用全解析

文章目录 一、四字命令基础二、四字命令详解三、四字命令的开启与配置四、结合业务解读四字命令confconsenvi命令Stat命令MNTR命令ruok命令dump命令wchswchp ZooKeeper&#xff0c;作为一款分布式协调服务&#xff0c;提供了丰富的四字命令&#xff08;也称为四字短语&#xff…

MinGW-w64_10.0.0 + GCC12_x86_64-12.2.0-release-posix-seh-msvcrt-rt_v10-rev2.zip

主题&#xff1a;mingw-w64安装 以及 matlab适配mingw-w64&#xff0c;g&#xff0c;gcc 无套路直接下载mingw-w64 for matlab 通过百度网盘分享的文件&#xff1a; MinGW-w64_10.0.0 GCC12_x86_64-12.2.0-release-posix-seh-msvcrt-rt_v10-rev2.zip 链接&#xff1a;https…

SpringCloudalibaba 集成 Knife4j 的时候出现多余的 前缀

这里是在网关 GateWay 中集成的 Knife4j&#xff0c;并且使用的是 Knife4j 服务发现模式 问题 用户服务 接口地址&#xff1a;/api/user/login GateWay 服务 现像 打开 Knife4j 文档中接口地址前缀多了一个 /api/user 解决 参考链接 2.1 Spring Cloud Gateway集成Knife4j …

信息安全工程师(79)网络安全测评概况

一、定义与目的 网络安全测评是指参照一定的标准规范要求&#xff0c;通过一系列的技术、管理方法&#xff0c;获取评估对象的网络安全状况信息&#xff0c;并对其给出相应的网络安全情况综合判定。其对象主要为信息系统的组成要素或信息系统自身。网络安全测评的目的是为了提高…

【Leecode】Leecode刷题之路第46天之全排列

题目出处 46-全排列-题目出处 题目描述 个人解法 思路&#xff1a; todo代码示例&#xff1a;&#xff08;Java&#xff09; todo复杂度分析 todo官方解法 46-全排列-官方解法 预备知识 回溯法&#xff1a;一种通过探索所有可能的候选解来找出所有的解的算法。如果候选解…

机器学习—选择激活函数

可以为神经网络中的不同神经元选择激活函数&#xff0c;我们将从如何为输出层选择它的一些指导开始&#xff0c;事实证明&#xff0c;取决于目标标签或地面真相标签y是什么&#xff0c;对于输出层的激活函数&#xff0c;将有一个相当自然的选择&#xff0c;然后看看激活函数的选…

97_api_intro_imagerecognition_pdf2word

通用 PDF OCR 到 Word API 数据接口 文件处理&#xff0c;OCR&#xff0c;PDF 高可用图像识别引擎&#xff0c;基于机器学习&#xff0c;超精准识别率。 1. 产品功能 通用识别接口&#xff1b;支持中英文等多语言字符混合识别&#xff1b;formdata 格式 PDF 文件流传参&#xf…

不适合的学习方法

文章目录 不适合的学习方法1. 纯粹死记硬背2. 过度依赖单一资料3. 线性学习4. 被动学习5. 一次性学习6. 忽视实践7. 缺乏目标导向8. 过度依赖技术9. 忽视个人学习风格10. 过于频繁的切换 结论 以下是关于不适合的学习方法的更详细描述&#xff0c;包括额外的内容和相关公式&…

刷题笔记——栈和队列互相冒充

刷题笔记——栈和队列互相冒充 5.3 用队列实现栈两队列实现栈一个队列实现栈 5.4 用栈实现队列两栈实现队列push栈和pop栈一个栈实现队列 5.3 用队列实现栈 原OJ题&#xff1a;225. 用队列实现栈 - 力扣&#xff08;LeetCode&#xff09; 两队列实现栈 入栈的实现 选非空的…

Mysql基础 01 数据与sql

文章目录 一、基本概念二、mysql的常用命令三、sql规范四、数据类型五、SQL语句 一、基本概念 数据库(database,DB)&#xff1a;存储数据的仓库。 数据库管理系统软件(Database Management System,DBMS)&#xff1a;是一种操作和管理数据库的大型软件。常见的DBMS有oracle、s…

5G NR:各物理信道的DMRS配置

DMRS简介 在5G中&#xff0c;DMRS&#xff08;DeModulation Reference Signal&#xff09;广泛存在于各个重要的物理信道当中&#xff0c;如下行的PBCH&#xff0c;PDCCH和PDSCH&#xff0c;以及上行的PUCCH和PUSCH。其最为重要的作用就是相干解调&#xff08;Coherence Demodu…

从零开始:利用Portainer CE和cpolar搭建NextCloud私有云存储

文章目录 前言1. 在PortainerCE中创建NextCloud容器2. 公网远程访问本地NextCloud容器2.1 内网穿透工具安装3.2 创建远程连接公网地址 3. 固定NextCloud私有云盘公网地址 前言 本文将介绍如何在本地利用Portainer CE的可视化界面创建NextCloud私有云盘容器&#xff0c;并通过c…

第三十七章 Vue之编程式导航及跳转传参

目录 一、编程式导航跳转方式 1.1. path 路径跳转 1.1.1. 使用方式 1.1.2. 完整代码 1.1.2.1. main.js 1.1.2.2. App.vue 1.1.2.3. index.js 1.1.2.4. Home.vue 1.1.2.5. Search.vue 1.2. name 命名路由跳转 1.2.1. 使用方式 1.2.2. 完整代码 1.2.2.1. main.js 1…

人工智能(AI)和机器学习(ML)技术学习流程

目录 人工智能(AI)和机器学习(ML)技术 自然语言处理(NLP): Word2Vec: Seq2Seq(Sequence-to-Sequence): Transformer: 范式、架构和自注意力: 多头注意力: 预训练、微调、提示工程和模型压缩: 上下文学习、思维链、全量微调、量化、剪枝: 思维树、思维…

升级改进策略:鸡只图像分割

鸡只图像分割系统源码&#xff06;数据集分享 [yolov8-seg-rtdetr&#xff06;yolov8-seg-p2等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI Global Al lnnovation C…

1.62亿元!812个项目立项!上海市2024年度“科技创新行动计划”自然科学基金项目立项

本期精选SCI&EI ●IEEE 1区TOP 计算机类&#xff08;含CCF&#xff09;&#xff1b; ●EI快刊&#xff1a;最快1周录用&#xff01; 知网(CNKI)、谷歌学术期刊 ●7天录用-检索&#xff08;100%录用&#xff09;&#xff0c;1周上线&#xff1b; 免费稿件评估 免费匹配期…

软件设计师下午题UML15分

一、涉及到的图及对应关系 二、例题 1.用例图和类图的例题 解析及答案 2.状态图和类图的例题 3.通信图和类图例题 例题

如何找到养生生活视频素材?推荐几个优秀网站

今天&#xff0c;我们来聊一个实用的话题&#xff0c;那就是如何找到优质的养生视频素材。作为自媒体创作者&#xff0c;高质量的视频素材对内容制作至关重要。不论你是刚入行的新手&#xff0c;还是已经积累了一定粉丝的大V&#xff0c;找到合适的养生视频素材都能帮助你更好地…

书生大模型第四期闯关任务与笔记

书生大模型第四期闯关任务与笔记 入门岛第一关 Linux闯关任务&#xff1a;完成SSH连接与端口映射并运行hello_world.py笔记与过程SSH端口映射linux文件管理命令linux进程管理命令 第二关 Python闯关任务&#xff1a;Leetcode 383(笔记中提交代码与leetcode提交通过截图)闯关任务…

Zabbix 7 最新版本安装 Rocky Linux 8

前言 本实验主要在Rocky Linux 中安装Zabbix&#xff0c;其他centos8、Debian、Ubuntu、Alma Linux都可以安装&#xff0c;就是在中间件有点不同。Nginx就要配置一下&#xff0c;官网给的教程也算是很规范的&#xff0c;就是在MySQL上要自己安装&#xff0c;他没有告诉我们&am…