【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\nint n = content.size();string s = to_string(n);s += '\n';s += content;s += '\n';return s; } string prase(string &package) {//len \n content \nsize_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 _ystring 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 _codestring 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
注意:
- 像网站这种,一般默认会添加协议方案名,且协议方案名对应唯一一个端口号,所以即使不写端口号,也没关系(如:http 对应端口号 80,https 对应端口号 443)
- web根目录不一定是linux系统下的根目录,具体指什么,完全由服务器那边解释
(三)urlencode(编码) 和 urldecode(解码)
像 / ? : 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现
所以,如果某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义.
转义的规则如下(这个过程叫编码):
将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式
编码解码工具:
URL 编码解码 - Codeeeee 在线小工具
4. HTTP协议格式
注意:
- 上图对应格式是打印出来的格式,实际上,发送到网络上的是整个字符串,是连在一起的
- http也是一种协议,它也需要将数据序列化,反序列化
代码
5. HTTP的方法
其中最常用的就是 GET方法 和 POST方法
注意:
- GET 方法 和 POST 方法都可以传参
- GET 方法的参数是在 url 内的,通过 url 提交的,POST 方法的参数是在正文内
- POST 方法 比 GET 方法更加私密
GET 方法:
POST 方法:
6. HTTP的状态码
最常见的状态码, 比如 200(OK), 404(Not Found,一般是客户端要访问的文件不存在), 403(Forbidden), 302(Redirect, 重定向), 504(Bad Gateway)
注意:
- 3XX代表的重定向有两种:一种是临时移动,另一种是长期移动
- 长期移动:一旦设置了永久重定向,所有后续对原始URL的请求都应该被自动转发到新的URL,而且这个重定向是长期有效的;临时移动:表明资源的移动是暂时的。 客户端在接收到临时重定向响应后,会临时使用新的URL,但在将来的某个时间点,对原始URL的请求可能会恢复为直接访问原始资源,而不是被重定向
HTTP常见Header
Content-Type: 数据类型(text/html等)
Content-Length: Body的长度
Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
User-Agent: 声明用户的操作系统和浏览器版本信息;
referer: 当前页面是从哪个页面跳转过来的;
location: 搭配3xx状态码使用, 告诉客户端接下来要去哪里访问;
Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能
注意:
- Content-Type : 指明访问的路径是什么类型(如:.html : 网页 ; .jpg :jpg格式的图片 ;.png : png格式的图片 ...... )
- Cookie : Cookie文件可能是内存级的(储存在内存里),也可能是文件级的(储存在磁盘里)
- cookie文件的内容保存多久,一般是由浏览器决定的,如果内容没有了,则下一次访问对应服务器,仍要进行验证
- http协议默认是无状态的
- http对登入用户的会话保持功能
7. 长连接和短连接
- 即使是一个网页,也可能包含很多元素,每一个元素,都要进行一次http请求,即建立一个tcp连接,就会发生多个请求和响应,这就是长连接
- 只有一次请求和响应,连接就断开的,就是短连接
相关文章:

【linux】再谈网络基础(一)
1. 再谈 "协议" 协议是一种 "约定",在读写数据时, 都是按 "字符串" 的方式来发送接收的. 但是这里我们会遇到一些问题: 如何确保从网上读取的数据是否是完整的,区分缓冲区中的由不同客户端发来的数据 2. 网…...

Unknown at rule @tailwindscss(unknownAtRules)
一、前言 整合 tailwindcss 后,发现指令提示警告 Unknown at rule tailwindscss(unknownAtRules),其实是 vscode 无法识别 tailwindscss 指令,不影响使用,但是对于我这种有编程洁癖的人来说,有点膈应。 二、解决方案…...

IDEA - 快速去除 mapper.xml 黄色警告线和背景色----简化版
1.打开设置 2.去掉黄色警告线设置 3.去掉背景色设置 4.示范图...

高级 SQL 技巧详解
文章目录 高级 SQL 技巧详解一、引言二、窗口函数1、窗口函数的使用1.1、RANK() 函数示例1.2、常用窗口函数 三、公共表表达式(CTE)2、CTE 的使用2.1、CTE 示例 四、索引优化3、索引的创建与优化3.1、创建索引3.2、索引类型与注意事项 五、事务管理4、事…...

移除元素(java)
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。 假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作: 更改…...

【Linux】shell脚本:检测文件是否存在,如存在则删除
通常,可以使用[ -f <file> ]来检查文件是否存在,使用rm <file>来删除文件。 以下是一个示例脚本,用于检测一个文件是否存在,并在存在时删除它: #!/bin/bash # 定义要检查的文件路径 file_path"/…...

Git代码托管(三)可视化工具操作(1)
常见的可视化操作工具有 一、官方网页 如码云、gitlab,自带了常见的git操作。 以码云为例: 1、创建分支: 进入分支目录,点击 新建分支 按钮, 在弹出框中输入新分支名称,点击确定即可一键创建分支&…...

How to use ffmpeg to convert video format from .webm to .mp4
The .mp4 container format doesn’t support the VP8 codec, which is commonly used in .webm files. MP4 containers typically use the H.264 codec for video and AAC for audio. You’ll need to re-encode the video using the H.264 codec and re-encode the audio us…...

Halcon 从XML中读取配置参数
1、XML示例 以下是一个XML配置文件的示例,该文件包含了AOI(自动光学检测)算法的环境参数和相机逻辑参数: <AOI><!--AOI算法参数 20241106--><Env><!--环境参数--><Param name="GPUName" value="NVIDIA GeForce RTX 405…...

hive表内外表之间切换
你想把内表和外表在元数据上达到切换的目的,这个操作有个前提,在apache版本源码上来讲是支持的!!!!但是!!!!注意哦!默认情况下apache版本的源码中…...

电子邮件营销软件哪个好?
在数字化时代,电子邮件营销仍然是企业与客户沟通的核心策略之一。无论是推广新产品、发送新闻简报,还是进行客户关系管理,选择合适的电子邮件营销软件至关重要。面对市场上众多的选择,企业如何才能找到最适合自己的工具呢…...

OpenAI大事记;GPT到ChatGPT参数量进化
目录 OpenAI大事记 GPT到ChatGPT参数量进化 OpenAI大事记 GPT到ChatGPT参数量进化 ChatGPT是从初代 GPT逐渐演变而来的。在进化的过程中,GPT系列模型的参数数量呈指数级增长,从初代GPT的1.17亿个参数,到GPT-2的15 亿个参数,再到 GPT-3的1750 亿个参数。模型越来越大,训练…...

springboot020基于Java的免税商品优选购物商城设计与实现
🍅点赞收藏关注 → 文档最下方联系方式领取本源代码、数据库🍅 本人在Java毕业设计领域有多年的经验,陆续会更新更多优质的Java实战项目希望你能有所收获,少走一些弯路。🍅关注我不迷路🍅 一 、设计说明 1…...

代码随想录之字符串刷题总结
目录 1.反转字符串 2.反转字符串II 3.替换数字 4.翻转字符串里面的单词 5.右旋&&左旋字符串 1.反转字符串 题目描述: 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。 不要给另外的数组分配额外…...

PS-基础学习(常用快捷键1.2-1.3)
常用快捷键 钢笔操作功能Alt 选择工具使用选择工具放到锚点上,按下alt,然后放到调整曲度的上面,可以修改一边的曲度可以修改出不平滑的转折点选择工具放到锚点上进行拖拽可以移动锚点的位置ctrl 选择工具使用选择工具,按住ctrl…...

qt QListView详解
1、概述 QListView 是 Qt 框架中的一个视图类,用于展示模型中的数据。它基于 QAbstractItemView,支持多种视图模式,如列表视图(List View)、图标视图(Icon View)等。QListView 是模型/视图框架…...

287. 寻找重复数
目录 题目我的解法解法 题目 给定一个包含 n 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。 假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。 你设计的解决方案…...

2024年最受欢迎的编程语言
No.1 JavaScript / TypeScript 自从创建第一个网站以使其动态化以来,JavaScript多年来一直受到欢迎。话虽如此,目前JavaScript是整个市场上需求量最大的编程语言。此外,TypeScript(一种具有类型安全性的JavaScript超集࿰…...

C++ 线程初始化编译报错
这是一个很简单的开启一个线程, 用于演示一个线程和生命周期之间的错误,但是还没有把这个错误暴露出来, 就遇见了一个编译问题. 线程中执行指定逻辑的代码 线程的执行方法, 声明写在了ThreadRun.h 实现写在 ThreadRun.cpp中. class ThreadRun { public: void func(); };void T…...

[MySQL]视图
视图是什么 视图(View)是一种虚拟存在的表。视图中的数据,来自定义视图的查询语句中,使用的表,并且是在使用视图时动态生成的。 简单讲,视图只保存了查询的SQL逻辑,不保存查询结果。所以我们在…...

Windows Server2012 R2搭建NFS服务器
正文共:1024 字 23 图,预估阅读时间:1 分钟 在测试vCenter的集群操作时,出现了共享vSAN错误的问题,导致无法继续。我也只好先创建一个共享NFS(Network File System,网络文件系统)存储…...

SQL题:使用hive查询各类型专利top 10申请人,以及对应的专利申请数
一、题目以及介绍 题目介绍: 1、表名:t_patent_detail (专利明细表) 2、表字段:专利号(patent_id)、专利名称(patent_name)、专利类型(patent_type)、申请时间(aplly_date)、授权时间(authorize_date)、申请人(apply_…...

使用sealos部署的集群在部署metrics-server时日志x509
1、下载文件并进行部署 wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml2、进行部署 kubectl apply -f components.yaml3、发现问题 pod容器已经启动但是健康检查没有通过 kubectl get pod -n kube-system metrics-server…...

WPF怎么通过RestSharp向后端发请求
1.下载RestSharpNuGet包 2.请求类和响应类 public class ApiRequest {/// <summary>/// 请求地址/// </summary>public string Route { get; set; }/// <summary>/// 请求方式/// </summary>public Method Method { get; set; }/// <summary>//…...

promise的用法以及注意事项,看了这篇你就会了
一,为什么要使用promise,ta能解决那些问题? Promise 是异步编程的一种解决方案: 从语法上讲,Promise是一个对象,从它可以获取异步操作的消息;从本意上讲,它是承诺,承诺它过一段时间…...

vue3如何使用pinia设置全局状态,附常见面试题
1. stores/index.ts 文件 在 index.ts 中创建 store 实例并封装了注册逻辑,这样可以方便地将整个 Pinia 实例注册到 Vue 应用中。代码如下: import type { App } from vue import { createPinia } from piniaconst store createPinia()// 全局注册 st…...

lerna+umi ‘max‘ 不是内部或外部命令,也不是可运行的程序
lerna不管version7还是老版都报 $ max setup max 不是内部或外部命令,也不是可运行的程序 或批处理文件。 error Command failed with exit code 1. 这点问题是因为lerna没编译完成; 解决: 首先我们在lerna packages 里用cli 安装umi;然后…...

美格智能5G车规级通信模组: 5G+C-V2X连接汽车通信未来十年
自2019年5G牌照发放开始,经过五年发展,我国5G在基础设施建设、用户规模、创新应用等方面均取得了显著成绩,5G网络建设也即将从基础的大范围覆盖向各产业融合的全场景应用转变。工业和信息化部数据显示,5G行业应用已融入76个国民经…...

「C/C++」C/C++ 指针篇 之 指针运算
✨博客主页何曾参静谧的博客📌文章专栏「C/C」C/C程序设计📚全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…...

计算机网络网络层笔记
互联网提供的两种服务 1.虚电路服务 2.数据报服务 需要记住的是现在只用第二种也就是数据报服务 网际协议IP 物理层的中断系统:转发器(hub) 链路层的中断系统:交换机 网络层的中断系统:路由器 网络层以上:网关 如上图所示,网关是用来访问其他的网段的一个接口,网关的地…...