【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逻辑,不保存查询结果。所以我们在…...
被AI冲击的App,反成了Agent的命门
2026年最流行的一个判断:AI Agent要吃掉一切图形界面,对话即服务,App即将消亡。 这个判断的依据并非没有道理。Agent确实在接管"发现"和"调度"——用户不再需要主动打开某个App,而是告诉Agent"帮我订一…...
Best Practice for AI Agents Project _ Chapter 1
很高兴he大家分享,《AI智能体项目最佳实践》内容,系统覆盖从单智能体工程基础,到私有知识注入、能力扩展、安全设计,再到多智能体协同的完整企业AI落地路径。本次分享第一章:从模型调用到可靠的单智能体(Fr…...
靖江注册公司需要多少钱?2026最新费用明细与隐形消费避坑指南
对于靖江的传统小微型企业、个体工商户、夫妻店及初创公司而言,注册公司的费用多少、是否存在隐形消费,是创业初期最关心的问题。这类企业大多没有专职会计,社保参保人数通常在3人以下,注册年限多在2年内,资金预算有限…...
5G网络切换实战:当gNB之间没有Xn接口时,N2/NGAP切换如何保证你的游戏不掉线?
5G网络无缝切换实战:无Xn接口场景下的高可靠连接方案 手游玩家小张正沉浸在激烈的团战中,突然屏幕右上角的延迟数字从30ms飙升至500ms——角色瞬间卡顿,等他重新恢复操作时,团队已经团灭。这种场景在5G时代本应成为历史࿰…...
CANN/asc-devkit Tiling模板参数选择宏
ASCENDC_TPL_SEL_PARAM 【免费下载链接】asc-devkit 本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。 项目地址: https://…...
告别臃肿PDF!用Ghostscript命令行批量压缩/拆分/合并的保姆级教程
Ghostscript实战指南:PDF批量处理的高效命令行艺术 每次面对动辄上百兆的扫描版PDF报告时,你是否也经历过邮箱附件发送失败、云盘上传卡在99%的崩溃瞬间?当领导临时要求合并二十份季度报表,或是学术期刊需要按章节拆分投稿时&…...
别再只用按键了!用STM32F103的ADC读取电位器,给你的无感无刷电机做个“油门”
从油门踏板到电机转速:STM32F103 ADC精准控制无刷电机的交互设计艺术 清晨的咖啡机发出均匀的研磨声,电动滑板车在街道上流畅加速,这些看似简单的机械运动背后,都隐藏着一个精妙的交互设计——如何让人类的手部动作与电机转速建立…...
如何使用谷歌全新AI智能体,实现超越普通搜索的信息追踪
在谷歌 I/O 2026 开发者大会主题演讲中,这家科技巨头宣布了搜索功能中全新的智能体能力。用户现在可以创建、自定义并管理多个 AI 智能体,以便持续获取感兴趣话题的最新动态。此次发布是谷歌大力推进智能体 AI 系统战略的重要组成部分,这类系…...
阿里云峰会大切换:云计算三十年首换用户,全栈重做能否驱动飞轮?
【阿里云峰会现场,信息量惊人】5月20号,在杭州举办的阿里云峰会,场馆外早已排起长队。原本以为只是例行发布会,进去后却发现展区密度远超预期。AI原生应用全家桶、合作伙伴展台,还有超节点服务器实体,一路看…...
别让中文路径坑了你!FaceFusion在Windows和Mac上的完整环境配置与文件规范指南
别让中文路径坑了你!FaceFusion在Windows和Mac上的完整环境配置与文件规范指南 在数字创意领域,FaceFusion作为一款强大的AI换脸工具,正受到越来越多内容创作者的青睐。然而,许多用户在初次接触时往往会被一系列看似莫名其妙的错误…...

