计算网络原理 第三章 数据链路层 数据链路层(一)3.1 使用点对点信道的数据链路层3.1.1 数据链路层和帧3.1.2 三个基本问题 数据链路层的信道类型3.2 点对点协议 PPP3.2.1 PPP协议的特点3.2.2 PPP协议的帧格式3.2.3 PPP协议的工作状态 3.3 使用广播信道的数据链路层(局域网)3.3.1 局域网的数据链路层 数据链路层(一) 3.1 使用点对点信道的数据链路层 3.1.1 数据链路层和帧 数据发送模型
数据链路层的信道类型
数据链路层使用的信道主要有以下两种类型:
点对点信道。这种信道使用一对一的点对点通信方式。广播信道。这种信道使用一对多的广播通信方式,因此过程比较复杂。广播信道上连接的主机很多,因此必须使用专用的共享信道协议来协调这些主机的数据发送。 .
.
链路与数据链路
**链路(link)**是一条无源的点到点的物理线路段,中间没有任何其他的交换结点。 一条链路只是一条通路的一个组成部分。
数据链路(data link) 除了物理线路外,还必须有通信协议来控制这些数据的传输。若把实现这些协议的硬件和软件加到链路上,就构成了数据链路。 现在最常用的方法是使用适配器(即网卡)来实现这些协议的硬件和软件。一般的适配器都包括了数据链路层和物理层这两层的功能。 帧
数据链路层传送的是帧
.
.
3.1.2 三个基本问题 1.封装成帧
封装成帧(framing) 就是在一段数据的前后分别添加首部和尾部,然后就构成了一个帧。确定帧的界限。
首部和尾部的一个重要作用就是进行帧定界。
用控制字符进行帧定界的方法举例
试想:帧还未发送完,发送端出了问题,只能重发该帧。接收端却收到了前面的“半截子帧”,它会抛弃吗?为什么?
2.透明传输
若传输的数据是ASCII码中“可打印字符(共95个)“集时,一切正常。
若传输的数据不是仅由”可打印字符”组成时,就会出问题,如下
用字节填充法解决透明传输问题
发送端的数据链路层在数据中出现控制字符“SOH”或“EOT”的前面插入一个转义字符“ESC”(其十六进制编码是 1B)。
字节填充(byte stuffing)或字符填充(character stuffing)——接收端的数据链路层在将数据送往网络层之前删除插入的转义字符。
如果转义字符也出现数据当中,那么应在转义字符前面插入一个转义字符。当接收端收到连续的两个转义字符时,就删除其中前面的一个。
当传送的帧是用文本文件组成的帧时(文本文件中的字都是从键盘上输入的),其数据部分显然不会出现像SOH或EOT这样的帧定界控制字符。可见不管从键盘上输入什么字符都可以放在这样的帧中传输过去,因此这样的传输就是透明传输。
.
.
3.差错控制
在传输过程中可能会产生比特差错:1 可能会变成 0 而 0 也可能变成 1。
在一段时间内,传输错误的比特占所传输比特总数的比率称为误码率 BER (Bit Error Rate)。
PostgreSQL的ON CONFLICT PostgreSQL 的 upsert 简介 PostgreSQL 的 upsert 功能:当记录不存在时,执行插入;否则,进行更新。
PostgreSQL 的 upsert 简介 在关系数据库中,术语 upsert 被称为合并(merge)。意思是,当执行 INSERT 操作时,如果数据表中不存在对应的记录,PostgreSQL 执行插入操作;如果数据表中存在对应的记录,则执行更新操作。这就是为什么将其称为 upsert(update or insert)的原因。
通过 INSERT ON CONFLICT 来使用 upsert 功能:
INSERT INTO table_name(column_list) VALUES(value_list) ON CONFLICT target action; target 可以是:
(column_name):一个字段名ON CONSTRAINT constraint_name:其中的 constraint_name 可以是一个唯一约束的名字WHERE predicate:带谓语的 WHERE 子句 action 可以是:
DO NOTHING:当记录存在时,什么都不做DO UPDATE SET column_1 = value_1, … WHERE condition:当记录存在时,更新表中的一些字段 注意,ON CONFLICT 只在 PostgreSQL 9.5 以上可用。
PostgreSQL 的 upsert 示例
文章目录 1. 监听属性值的变化 - watch2. 组件创建 - component2.1 全局组件2.2 局部组件 3 组件间的通信3.1 父向子组件传递数据 - props3.1.1 动态绑定3.1.2 静态绑定 3.2 子向父组件传递数据 - v-bind:属性绑定3.3 非父子组件间的传递信息 4 组件的插槽 - slot4.1 无名插槽4.2 有名插槽 - 意味一个组件可写多个插槽4.2.1 不使用标签4.2.2 使用标签 4.3 作用域插槽 1. 监听属性值的变化 - watch 语法要求:watch里面的函数名必须跟date里面属性名一致
<body> <div id="vueBox"> <p>{{num}}</p> <button v-on:click="add">添加</button> </div> </body> <script type="text/javascript"> var vue = new Vue({ el: "#vueBox", data: { num: 0 }, methods: { add: function() { this.num++; } }, watch: { num: function(newValue, oldValue) { console.
http://www.jq22.com/yanshi941
http://sc.chinaz.com/jiaobendemo.aspx?downloadid=9201794959530
会话技术的概述 什么是会话 会话简单理解为:用户打开一个浏览器,点击多个超链接访问服务器的web资源,然后关闭浏览器,整个过程称为是一次会话。
为什么要学习会话技术 每个用户与服务器进行交互过程中,产生一些各自的数据,程序想要把这些数据进行保存,就需要使用会话技术。
例如:用户点击超链接购买一个商品, 程序应该保存用户所购买的商品,以便于用户点击结账可以得到用户所购买的商品信息。
思考:用户购买的商品保存在request或ServletContext中是否可以?
答案是不可以的。
会话技术的分类 session和cookie作用原理、区别
Cookie技术 Cookie是客户端技术,程序把每个用户的数据以cookie的形式保存到各自浏览器中。当用户使用浏览器再次访问服务器中的web资源的时候,就会带着各自的数据(cookie)过去。这样, web资源处理的就是用户各自的数据(cookie)了。
Cookie技术的实现原理 Http Cookie机制及Cookie的实现原理
客户端请求服务器后,如果服务器需要记录用户状态,服务器会在响应信息中包含一个Set-Cookie的响应头,客户端会根据这个响应头存储Cookie信息。再次请求服务器时,客户端会在请求信息中包含一个Cookie请求头,而服务器会根据这个请求头进行用户身份、状态等较验。
当用户访问一个网站需要登录,输入完账号和密码点击登录后,发送请求到服务器,服务器接收到请求后记录用户的登录状态(账号密码),响应是就会在响应头中携带一个Set-Cookie字段(账号密码),客户端接收到响应后就会在本地(内存或硬盘)中储存Set-Cookie字段,当再次请求时,将会在请求头中包含服务器响应的Cookie信息,因此用户再次访问网站时就不需要登录了。
Session技术 Session是服务器端技术,利用这个技术,服务器在运行时为每一个用户的浏览器创建一个独享的session对象。
由于session为用户浏览器独享,所有用户在访问服务器的时候,可以把各自的数据放在各自的session 中,当用户再次访问服务器中的web资源的时候,其他web资源再从用户各自的session中取出数据为用户服务。
Session技术的实现原理 Session的原理
记录用户上次的访问时间 分析需求和流程 记录用户上次访问时间的代码实现 获得从浏览器带过来的Cookie 通过HTTPServletRequest对象中的方法:
想浏览器回写Cookie 通过HTTPServletResponse对象中的方法:
Cookie的构造 案例代码实现 创建一个web项目
创建包结构 代码实现 编写工具类:
/** * 查找指定名称Cookie的工具类 * * @author 25858 * */ public class CookieUtils { public static Cookie findCookie(Cookie[] cookies, String name) { if (cookies == null) { // 浏览器没有携带Cookie return null; } else { for (Cookie cookie : cookies) { // 判断cookie是否是我们想要的那个cookie // public String getName():返回 Cookie 的名称。创建后无法更改名称。 if (cookie.
C/C++中的函数 int func(int a, int b) { return a+b; } 在C/C++中,函数定义出,必须要有以下部分
函数名返回值类型参数列表return进行返回
优点:比较精细,使用起来比较收约束,但是在该约束的情况下使用比较方便。 shell中的函数 一般shell中的函数用来做一些shell的集合,这样可以使整个过程集合在一起,不会丢下某部分或者跳过某部分。
函数的定义有两种方法 1. 加上function关键字进行定义 #!/bin/bash #by author dhy #test function function func1() #加关键字的定义 { echo "this is the first function!" } 2. 省去关键字,直接定义 func1() #直接定义 { echo "this is the first function!" } 语法和作用 #!/bin/bash #by author dhy #test function func1() { echo "this is the first function!" } echo "--------func begin--------" func1 echo "--------func end----------"
韩立刚老师教学视频笔记
图片源自韩立刚老师的教学视频和谢希仁PPT,侵删
计算机网络原理 第二章 物理层 2.1 物理层的基本概念2.2 数据通信的基础知识相关术语有关信道的几个基本概念 2.3 物理层下面的传输媒体2.4 信道复用技术2.5 数字传输系统2.6 宽带接入技术 2.1 物理层的基本概念 物理层解决如何在连接各种计算机传输媒体上传输bit流,注意,不是指用什么传输媒体(介质)
物理层主要任务:确定传输媒体接口的一些特性:(为了统一规划,标准化,各个厂商生产一致,可以通用)
机械特性:接口形状 大小 引线数目 网线内有几根线
电气特性:例如规定电压范围
功能特性:例如规定-5V表示0 +5V表示1(电压信号代表数字信号)
过程特性:(规程特性)规定建立连接时各个部件的工作步骤
2.2 数据通信的基础知识 数据通信模型(图)
相关术语 通信的目的是传送消息
数据(data):运送消息的实体
信号(signal):数据的电气或电磁表现
–模拟信号:代表消息的参数取值连续(如电压高低电平代表01数据)–数字信号:代表消息的参数取值离散 码元(code):在使用时间域的波形表示数字信号时,则代表不同
离散数值的基本波形就称为码元
在数字通信中常常用时间间隔相同的符号来表示一个二进制数字,这样的时间间隔内的信号称为二进制码元,而这个间隔被称为码元长度,1码元可以携带n bit的信息量
解释:
如果信号一共用2种可能,那么1码元代表1bit信息(只有高低电平)
如果信号一共用4种可能,那么1码元代表2bit信息,00 01 10 11,码元有四种可能,一码元代表2bit
……
如果信号一共用2的n次方种可能,那么1码元代表nbit信息。
有关信道的几个基本概念 信道一般表示向一个方向传送的信息的媒体。所以咱们说平常的信息线路往往包含一条发送信息的信道和一条接受信息的信道。
单向通信(单工通信)–只能发送或只能接收
例子:电视塔发送电视信号,但是电视无法向电视塔发送信号
双向交替通信(半双工通信)–双方可以收发,但是不能同时发送或同时接收
双向同时通信(全双工通信)–通信的双方可以同时发送和接收消息
例子:打电话
计算机通信大多数是半双工和全双工通信
基带信号(baseband)和带通信号(band pass)
前提:信号是会衰减的,比如人说话,当距离较远之后,声音就会听不到。
基带信号(baseband):来自信息源的信号。
带通信号(band pass):把基带信息经过载波调制后的信号(载波调制就是把信号的频率搬到较高的频段,以便传输)
因此,如果传输距离短,信息衰减可以接受,那就直接使用基带信号,如果距离长,信号衰减大,那就得通过调制将基带信号转换为带通信号,以减小衰减,接收方收到后再进行解调,分析成基带信号进行解读。
几种基本调制方法:
调幅
调频
调相
具体见图:
(数字信号的)编码格式:
单极性不归零码
双极性不归零码
单极性归零码
题目 请编写程序实现两个十六进制整数的加法。
例如:十六进制整数 3762 和 05C3,3762+05C3=3D25
十六进制整数 CB9 和 957,CB9+957=1610
格式 输入格式
第 1 行:一个整数 T (1≤T≤10) 为问题数。
接下来 T 行,每行输入两个十六进制整数 n 和 m (n,m 为不超过 200 位的十六进制整数),A~F 全部为大写字母。 两个整数之间用一个空格分隔。
输出格式
对于每个问题,输出一行问题的编号(0 开始编号,格式:case #0: 等)。然后对应每个问题在一行中输出两个十六进制整数相加的结果,字母全部用大写字母。
样例 input 3 3762 05C3 CB9 957 F 1 output case #0: 3D25 case #1: 1610 case #2: 10 code #include <iostream> #include <algorithm> #include <stack> #include <cstdio> using namespace std; int char2int(char x) { if (x >= '0' && x <= '9') return x - '0'; return x - 'A' + 10; } char int2char(int x) { if (x >= 0 && x <= 9) return x + '0'; return x - 10 + 'A'; } int main() { int n, i, j; cin >> n; char a[208],b[208]; stack<int>c, d, ans; for (i = 0; i < n; i++) { scanf("
code .不能快速打开当前路径的控制面板。
打开vscode 快捷键shift+command+p 后输入shell选择 Install ‘code’ command in PATH
kmalloc/kfree,vmalloc/vfree函数用法和区别
1.kmalloc
kmalloc内存分配和malloc相似,除非被阻塞否则他执行的速度非常快,而且不对获得空间清零.
说明:在用kmalloc申请函数后,要清零用memset()函数对申请的内存进行清零。
2.kamlloc函数原型:
#include
Void *kmalloc(size_t size, int flags);
(1)第一个参数是要分配的块的大小
(2)第二个参数是分配标志(flags),他提供了多种kmalloc的行为。
(3)第三个最常用的GFP_KERNEL;
A.表示内存分配(最终总是调用get_free_pages来实现实际的分配;这就是GFP前缀的由来)是代表运行在内核空间的进程执行的。使用GFP_KERNEL容许kmalloc在分配空闲内存时候如果内存不足容许把当前进程睡眠以等待。因此这时分配函数必须是可重入的。如果在进程上下文之外如:中断处理程序、tasklet以及内核定时器中这种情况下current进程不该睡眠,驱动程序该使用GFP_ATOMIC.
B.GFP_ATOMIC
用来从中断处理和进程上下文之外的其他代码中分配内存. 从不睡眠.
C.GFP_KERNEL
内核内存的正常分配. 可能睡眠.
D.GFP_USER
用来为用户空间页来分配内存; 它可能睡眠.
E.GFP_HIGHUSER
如同 GFP_USER, 但是从高端内存分配, 如果有. 高端内存在下一个子节描述.
F.GFP_NOFS,GFP_NOIO
这个标志功能如同 GFP_KERNEL, 但是它们增加限制到内核能做的来满足请求. 一个 GFP_NOFS 分配不允许进行任何文件系统调用, 而 GFP_NOIO 根本不允许任何 I/O 初始化. 它们主要地用在文件系统和虚拟内存代码, 那里允许一个分配睡眠, 但是递归的文件系统调用会是一个坏注意.
上面列出的这些分配标志可以是下列标志的相或来作为参数, 这些标志改变这些分配如何进行:
__GFP_DMA
这个标志要求分配在能够 DMA 的内存区. 确切的含义是平台依赖的并且在下面章节来解释.
__GFP_HIGHMEM
这个标志指示分配的内存可以位于高端内存.
__GFP_COLD
正常地, 内存分配器尽力返回"缓冲热"的页 – 可能在处理器缓冲中找到的页. 相反, 这个标志请求一个"冷"页, 它在一段时间没被使用. 它对分配页作 DMA 读是有用的, 此时在处理器缓冲中出现是无用的. 一个完整的对如何分配 DMA 缓存的讨论看"直接内存存取"一节在第 1 章.
31.【中级】单词倒排 之前有一个类似的题目,用的简单的方法:
#include <iostream> #include <string> using namespace std; int main() { string input, output; while (cin >> input) { output = input + ' ' + output; } cout << output << endl; return 0; } 然而并没有通过,所以还是老实的做吧:从前往后扫描字符串,遇到是单词就入vector,最后反向输出即可:
#include<iostream> #include<vector> #include<string> using namespace std; int main() { string str; while (getline(cin, str)) { vector<string>svec; svec.clear(); string temp = ""; for (int i = 0; i < str.size(); ++i) { if (str[i] >= 'a' && str[i] <= 'z' || str[i] >= 'A' && str[i] <= 'Z') temp += str[i]; else { if (temp.
文章目录 1 管理变量1.1 ansible 变量简介1.2 命名变量 2 定义变量3 playbook 中的变量3.1.常见方式:在 playbook 开头的 vars 块中3.2 在外部文件定义 playbook 变量3.3 定义变量和使用变量 3.4 主机变量和组变量3.4.1 定义主机变量和组变量3.5 使用已注册变量捕获命令输出3.6 管理变量的练习 4 管理机密4.1 介绍 ansible vault4.2 创建加密文件4.3 创建加密文件同时将密码保存4.4查看加密文件4.5 编辑现有的加密文件4.6 加密现有的文件4.7 解密4.8 更改加密文件密码4.9 运行加密的 playbook,没有密码则报错 5 管理事实5.1 描述 ansible 事实5.2 查看主机信息5.3 再将事实替换为动态的值5.4 使用 setup 模块显示所有事实信息5.5 关闭事实收集,开提升执行速度5.6 创建自定义事实5.7 使用魔法变量 6 练习6.1 创建自定义变量6.2 使用基本身份认证的 httpd6.2.1 创建基本文件6.2.2 创建剧本6.2.3 创建加密文件6.2.4 创建 files 目录6.2.5 拷贝文件到files目录6.2.6 修改workstation的发布目录6.2.7 交互式输入密码,进行语法检测6.2.8 执行6.2.9 验证是否成功6.2.10 总结 将 playbook 中的某些值使用变量代替,从而 简化 playbook 的编写 1 管理变量 1.
问题描述 需要定时执行docker内的命令,已经在宿主上编辑
crontab -e 经过查看命令任务确实存在
crontab -l 但是就是不执行
解决方案 docker执行命令去掉 -it
问题解决。
多线程
线程:https://zhuanlan.zhihu.com/p/56518031
线程安全:锁 https://zhuanlan.zhihu.com/p/57482990
ps:thread.start()运行run()是用native 修饰的start0()方法来调用C++的方法运行
ALOAM是秦通对LOAM的一个简化版本,没有IMU的信息,算是入手激光SLAM非常简单的程序了
代码:
https://github.com/HKUST-Aerial-Robotics/A-LOAM
数据:
链接: https://pan.baidu.com/s/1GaZ2eGZdfc-cluSc-bkQng 提取码: 9zsp
graph:
效果:
注释:
scanRegistration.cpp:
#include <cmath> #include <vector> #include <string> #include "aloam_velodyne/common.h" #include "aloam_velodyne/tic_toc.h" #include <nav_msgs/Odometry.h> #include <opencv/cv.h> #include <pcl_conversions/pcl_conversions.h> #include <pcl/point_cloud.h> #include <pcl/point_types.h> #include <pcl/filters/voxel_grid.h> #include <pcl/kdtree/kdtree_flann.h> #include <ros/ros.h> #include <sensor_msgs/Imu.h> #include <sensor_msgs/PointCloud2.h> #include <tf/transform_datatypes.h> #include <tf/transform_broadcaster.h> using std::atan2; using std::cos; using std::sin; //扫描周期, velodyne频率10Hz,周期0.1s const double scanPeriod = 0.1; //弃用前systemDelay帧初始数据 const int systemDelay = 0; //systemInitCount用于计数过了多少帧 //超过systemDelay后,systemInited为true即初始化完成 int systemInitCount = 0; bool systemInited = false; //激光雷达线数初始化为0 int N_SCANS = 0; //点云曲率, 400000为一帧点云中点的最大数量 float cloudCurvature[400000]; //曲率点对应的序号 int cloudSortInd[400000]; //点是否筛选过标志:0-未筛选过,1-筛选过 int cloudNeighborPicked[400000]; //点分类标号:2-代表曲率很大,1-代表曲率比较大,-1-代表曲率很小,0-曲率比较小(其中1包含了2,0包含了1,0和1构成了点云全部的点) int cloudLabel[400000]; //两点曲率比较 bool comp (int i,int j) { return (cloudCurvature[i]<cloudCurvature[j]); } //设置发布内容,整体点云,角点,降采样角点,面点,降采样面点,剔除点 ros::Publisher pubLaserCloud; ros::Publisher pubCornerPointsSharp; ros::Publisher pubCornerPointsLessSharp; ros::Publisher pubSurfPointsFlat; ros::Publisher pubSurfPointsLessFlat; ros::Publisher pubRemovePoints; //ros形式的一线扫描 std::vector<ros::Publisher> pubEachScan; //是否发布每行Scan bool PUB_EACH_LINE = false; //根据距离去除过远的点,距离的参数 double MINIMUM_RANGE = 0.
二分查找很简单,可是对于一个区间长度为n的数组,最大的比较次数为多少呢?
对于标准的二分查找,我们每次从区间[l,r)中取一个值,和中间值mid=(l+r)>>1进行比较,然后将数组分为[l,mid) [mid+1,r),即每次将区间长度x变为(x-1)>>1。最大比较次数显然是我们想要查找的数并不在数组中的时候,这样的话我们需要将区间长度变为0才能结束比较。这样直接分析有些困难,因此我们不妨换一个思路。
如果区间长度为1,显然最多比较1次
区间长度为2,最多比较2次([0,2) -> [0,1) -> [0,0))
区间长度为3,最多比较2次([0,3) -> [0,1) [2,3))
区间长度为4,最多比较3次([0,4) -> [0,2) -> [0,1))
因此我们不难得到规律:
如果最多比较x次,则区间长度为2^(x-1) ~ 2^x-1 对于区间长度y,最多比较logy+1次
我们对上述发现的规律进行归纳证明:
假设对于区间长度为2^(k-1) ~ 2^k-1的区间,最多比较k次
则对于区间长度为2^k ~ 2^(k+1)-1的区间,假设区间长度为x
如果区间长度为奇数,那么第一次比较以后左右两个区间的长度在2^(k-1) ~ 2^k-1之间,加上第一次比较,最多比较k+1次
如果区间长度为偶数,那么第一次比较以后较大的区间为长度为偶数的区间,此区间的长度仍然在2^(k-1) ~ 2^k-1之间,加上第一次比较,最多比较k+1次
综上对于区间长度为2^(k-1) ~ 2^k-1的区间,最多比较k次(k>=1),即对于区间长度y,最多比较logy+1次
数据链路层基本概念 路由器是网络层设备
数据链路层:数据管道,传输的是数据包加上发送地址,接收地址,校验的数据帧
数据链路层的信道类型:
点到点信道:使用一对一的点到点通信方式(两个设备之间直接使用网线相连)广播信道:使用一对多的广播信道方式,因此过程比较复杂。广播信道上连接的主机很多,因此必须使用专用的共享信道协议来协调这些主机的数据发送 链路:一条点到点的物理线路段,中间没有其他交换节点。一条链路只是一条通路的一个组成部分。
数据链路:除了物理线路外,还必须有通信协议来控制这些数据的传输。若把实现这些协议的硬件和软件加到链路上,就构成了数据链路。
现在最常用的方法是使用适配器(网卡)来实现这些协议的硬件和软件。一般的适配器都包括了数据链路层和物理层这两层的功能。 数据帧 数据帧=数据包+帧头+帧尾+物理层地址+校验值
数据链路层解决的问题 封装成帧 透明传输 字节填充解决透明传输
发送端的数据链路层在数据中出现控制字符SOH或EOT的前面插入一个转义字符ESC(0x1B)
接收端的数据链路在将数据发送给上一层的网络层的时候会删除前面的转义字符
如果转义字符也出现在数据当中,那么应该在转义字符前插入一个转义字符。当接收端收到两个连续的转义字符的时候就删除其中前面那个
因此只有如果接收数据中含有一个ESC那么一定是数据中开始字符或者结束字符。 差错控制 误码率(BER):传输错误的比特占所传输比特总数的比率。误码率和信噪比有很大的关系。
如果传送过程中出现错误,路由器发现错误后会直接丢掉这个帧。可靠传输由传输层实现。
循环冗余检验(CRC)
运算过程为加上x个0以后,用x+1位数作为除数(随便选一个)。每次进行异或操作。要确保每次会至少减少一位,意思是如果某次的余数的最高位位0,则商为0,如果最高位为1,则商为1.
帧检验序列FCS为运算的余数,可以通过多种方法得到,不一定是CRC
最后传输的数据是数据加上FCS,如果余数不为0,则丢弃 特点:
这种检测方法不能确定究竟是哪一个或哪几个比特出现了差错如果除数选择的足够好(位数足够长),那么检错能力就很强 使用循环冗余检验(CRC)差错检测技术只能做到无差错接受。
无差错接收:凡是接收的帧我们几乎都能认为是没有差错的。
要做到可靠传输(发送什么接收什么)就必须加上确认和重传机制
CRC是一种无比特差错,而不是无传输差错的检测机制。虽然数据链路层要求做成无传输差错的,但是目前没有做到。
两种情况下的数据链路层 点对点通信 使用PPP协议,用于点到点通信。全世界用的最多的数据链路层协议。
PPP协议特点:
简单封装成帧透明传输差错检验多种网络层协议:可以在PPP协议种封装TCP/IP协议,可以封装IPX,SPx协议多种数据链路检测连接状态最大传送单元网络层地址协商数据压缩协商
缺点:不能纠错不能流量控制不能得到序号不支持多点线路不支持半双工或单工链路 PPP协议的组成 数据链路层协议可以用于异步串行或者同步串行介质使用LCP(链路控制协议)建立并维护数据链路连接
ADSL拨号上网账号密码正确、有网费数据链路层才会通。即LCP有身份验证和计费功能网络控制协议(NCP)允许点到点连接上使用多种网络层协议 PPP协议帧格式 A段是地址,因为是点对点传输,所以是固定的FF,没有起什么作用
C段是控制字段,但是没有使用,一般是03
协议中的两个字节表示数据包中是什么内容
标志字段F=0x7E
PPP是面向字节的,所有PPP帧的长度都是整数字节
字节填充实现透明传输
将信息字段中出现的每个0x7E(01111111)字节转换成0x7D 0x5E(0111111001011111)
如果信息字段中出现0x7D(01111110)的字节,则将其转换为2字节序列(0x7D,0x5D(0111111001011110))
如果信息字段中出现ASCLL码的控制字符(数值小于0x20)则在前面加入一个0x7D
最后接收的时候再转换为原来的信息
零比特填充方法实现透明传输
如果信息字段发送的不是字节,而是二进制流,则在发送端,只要发现5个连续的1就在其中填入一个0。在接收的时候每接收5个1就删除一个0。
不使用序号和确认机制
在数据链路层出现差错概率不大时,使用比较简单的PPP协议比较合理
在因特网环境下,PPP的信息字段放入的数据是IP数据报。数据链路层的可靠传输并不能够保证网络层的传输也是可靠的
帧检验序列FCS字段可保证无差错接受
PPP协议的工作状态(拨号上网的过程):当用户拨号拨入ISP时,路由器的调制解调器对拨号做出确认,并建立一条物理连接。PC机向路由器发送一系列的LCP分组(封装成多个PPP帧)。这些分组及其响应选择一些PPP参数,进行网络层配置,NCP给新接入的PC机分配一个临时的IP地址,时PC机成为因特网上的一个主机。
通信完毕时,NCP释放网络层链接,收回原来分配出去的IP地址。接着,LCP释放数据链路层连接,最后释放物理层链接。
分析目标:
根据某电商近期的销售记录,对每月的购买人数、复购率、回购率、消费时间、消费群体等进行分析。
数据来源
orderinfo表:
create table orderinfo( orderid varchar(10) primary key, userid varchar(10), ispaid varchar(10), prince varchar(20), paidtime varchar(50)); userinfo表:
create table userinfo( userid varchar(10) primary key, sex char(2), brith varchar(50)); 导入数据:
本处用到MySQL自带的LOAD DATA INFILE的函数。对比了python的execute/executemany,LOAD DATA INFILE的速度真是非常快,谁用谁知道!
ps:如果用LOAD DATA INFILE,提示禁止加载本地数据;这必须在客户端和服务器端都启用。
那可能是加载本地文件没有开启,输入查看命令:show variables like 'local_infile';
然后开启:set global local_infile=on;
OK!
LOAD DATA LOCAL INFILE 'order_info.csv' into table orderinfo fields terminated by ','; LOAD DATA LOCAL INFILE 'user_info.csv' into table orderinfo fields terminated by ','; 处理数据
1.代码
#include<iostream> #include<thread> #include <mutex> using namespace std; mutex mymutex; //加入锁 void thread1(){ unique_lock<mutex> lock(mymutex); for(int i=0; i<30; i++){ cout<< "线程1运行" << endl; } }; void thread2(){ unique_lock<mutex> lock(mymutex); for(int i=0; i<30; i++){ cout<< "线程2运行" << endl; } }; int main() { thread t1(thread1); thread t2(thread2); t1.join(); t2.join(); return 0; } 2.运行结果
1.C++中的std::是什么?
std:: 是个名称空间标示符,C++标准库中的函数或者对象都是在命名空间std中定义的,所以我们要使用标准函数库中的函数或对象都要使用std来限定。
标准库在名字空间中被指定为std,所以在使用标准库中的函数或者对象的时候要加上std::,这样编译器就会明白我们调用的函数或者对象是名字空间std中的。
2.那么什么是C++标准库呢?
C++标准库,C++ Standard Library,是类库和函数的集合,其使用核心语言写成,由c++标准委员会制定,并不断维护更新。
C++强大的功能来源于其丰富的类库及库函数资源。在C++开发中,要尽可能地利用标准库完成,这样可以降低成本,提高编程效率,保证程序质量,又能保持编程风格一致性。
C++标准库又分为标准函数库和面向对象类库。
标准函数库包括:输入/输出 I/O、字符串和字符处理、数学、时间、日期和本地化、动态分配、其他、宽字符函数。
面向对象类库包括:标准的 C++ I/O 类、String 类、数值类、STL 容器类、STL 算法、STL 函数对象、STL 迭代器、STL 分配器、本地化库、异常处理类、杂项支持库。
3.那么在什么时候要用到std::,什么时候不需要用呢?
一般来说,要调用C++标准库时,要写上std::。
如果使用非标准库文件iostream.h,不用写。
如:#include<iostream.h>
#include<iostream.h> int main() { cout<<"hello world"; //而不是std::cout<<"hello world"; cout<<endl; //而不是std::cout<<std::endl; return 0; } 4.一种更简单的方法,不需要写std::
直接使用using namespace std来代替std::。
using namespace std 告诉编辑器我们将要使用空间std中的函数或者对象。
如:using namespace std;
#include<iostream> using namespace std; int main() { cout<<"hello world"; cout<<endl; return 0; }