百度地图-散点图(一)

我们使用数据(以DeSheng Zhang 老师提供的数据为例)中的PhoneData部分数据进行简单的测试,对于这部分数据,我们已经经过数据预处理的阶段。下面是对数据的直接使用。

构造所需要的SQL语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public String InsertData(List<String> lie){
String sql = "INSERT INTO "+lie.get(0)+"(";
String valueString = "";
if(lie.size()!=0) {
int len = lie.size();
for(int i=1;i<len-1;i++) {
sql+=(lie.get(i)+",");
valueString+="?,";
}
sql+=(lie.get(len-1)+") value("+valueString+"?);");

}else {
return null;
}
return sql;
}

数据读取

将我们存储好的格式数据,读取到系统空间中。
这个方法中,我们是暂时存储在list集合中的。
这个方法传入的参数是我们自定义的需要统计的数据的名称。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public List<List<String>> getDATA(List<String> lie) {
conn = JdbcUtils.getConnection();
String sql = tool.selectData(lie);
List<List<String>> ls = new ArrayList<List<String>>();
List<String> line = null;
try {
ps = conn.prepareStatement(sql);
rs= ps.executeQuery();
while(rs.next()) {
line = new ArrayList<String>();
line.add(rs.getString(1));
line.add(rs.getString(2));
line.add(rs.getString(3));
ls.add(line);
}
return ls;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}

格式转换与统计

对于每一个图所需要的数据的输入格式可能是不同的,对于小部分数据我们可以使用手动输入的方式,但是对于批量的数据,我们要尽可能的交给程序处理。因此,在接下来的学习中,会针对每一个图形模板提供一个数据格式。下面是将我们的数据处理成适合我们散点图的格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public String [] getInput(List<List<String>> ls) {
//这里主要进行两部分的拼接,
String[] data = new String[2];
data[0] = "var data =[";
data[1] ="var geoCoordMap = {";
int value =1;
for(int i=1;i<ls.size();i++) {
String jing =ls.get(i-1).get(1);
String wei = ls.get(i-1).get(2);
if(ls.get(i).get(1).equals(jing)&&ls.get(i).get(2).equals(wei)&&ls.get(i).get(0).equals(ls.get(i-1).get(0))) {
continue;
}
double a = (Math.random()*50)+10;
int b = (int)a;
if(ls.get(i).get(0).equals(ls.get(i-1).get(0))) {
value+=1;
}else {
value =1;
}
data[0]+="{name:'"+ls.get(i-1).get(0)+"_"+value+"', value:"+b+"},";
data[1]+="'"+ls.get(i-1).get(0)+"_"+value+"':["+ls.get(i-1).get(1)+","+ls.get(i-1).get(2)+"],";

}
data[0] +="{name:'"+ls.get(ls.size()-1).get(0)+"f', value:"+0+"}];";
data[1] +="'"+ls.get(ls.size()-1).get(0)+"f':["+ls.get(ls.size()-1).get(1)+","+ls.get(ls.size()-1).get(2)+"]};";
return data;
}

对于上述代码以及数据,因为没有提供要关注的点。因此,每条数据的value值,我们使用随机生成函数,随机生成一些数值作为我们每条数据的value值,用来模拟一个完整的过程。

实现的效果

部分数据的效果展示
在这里插入图片描述

需要优化的地方

  • 现在数据存储的位置是list,还应该继续优化到MAP集合中,这样在获取数据的时候就可以根据键拿值,而不是现在的get(0)没有意义。
  • 还需要编写一些经常用的统计函数。
  • 对于地图的界面展示还需要优化

数据预处理(一)

这部分的工作主要是对数据进行预处理。
我们在处理数据的时候一般会面对不同格式的数据,这样每次用数据的时候就需要重复执行或编写一些代码,这样就浪费了不少时间。这里先把数据(以DeSheng Zhang 老师提供的数据为例)进行第一步的预处理。

我的工作流程计划是:

1
2
3
4
graph LR
A[数据预处理] --> B[数据清洗]
B-->C[数据统计]
C-->D[数据可视化]
  • 在数据预处理阶段,主要进行的工作是对数据进行格式化,将所获得数据统一格式,这样方便后续工作。
  • 数据清洗阶段,将要进行的是对已经存储数据的质量进行分析,比如在收集的数据中,会存在一些数据值的缺失,数据乱序,或者一些重复数据的处理问题。
  • 数据统计阶段,是根据实际的需要对数据应用一些统计方法,进行分析,这部分是最重要的,也是需要我们花费更多的时间去学习的。
  • 数据可视化阶段是对数据以图的形式更直观的展现出来。会提供一些图的模版。
    最终实现的效果是,只需要上传数据就可以将数据映射到图中。

文件的读取

首先,将文件进行读取到系统中,这里仅是一个txt文件的实例。
对于xml等表格文件,还会继续学习。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class FileRead {
public List<List<String>> readFILE() {
File file = new File("文件路径");
//
List<List<String>> allList = new ArrayList<List<String>>();
BufferedReader reader = null;
try {
Reader inputStream = new FileReader(file);
reader = new BufferedReader(inputStream);
String line = null;
while((line = reader.readLine())!=null) {
String liString [] = line.split(",");
List<String> list = new ArrayList<String>();
for(String s:liString) {
list.add(s);
}
allList.add(list);
}
return allList;

} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}

数据的存储与格式化

将数据进行格式化,统一存储在数据库中,方便我们后续对数据进行存取操作,也易于数据的保存。

  1. 先是创建程序与数据库的连接操作,这里使用的是C3P0的连接方式,当然还有JDBC的连接方式。掌握一种就可以。
    这个类里面定义的是数据库连接所需要的一些基本的连接与关闭方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    public class JdbcUtils {
    //初始化连接池
    private static DataSource dataSource;
    static {
    dataSource = new ComboPooledDataSource();
    }
    public static DataSource getDataSource()
    {
    return dataSource;
    }
    //创建dbutil 常用工具类对象
    public static QueryRunner getQueryRunner() {
    return new QueryRunner(dataSource);
    }
    // 获取数据库连接对象
    public static Connection getConnection() {
    Connection conn = null;
    try {
    conn = dataSource.getConnection();
    } catch (Exception e) {
    e.printStackTrace();
    }
    return conn;
    }

    // 关闭数据库连接
    public static void close(Connection conn,PreparedStatement ps) {
    try {
    if (conn != null && conn.isClosed()) {
    conn.close();
    }
    if(ps!=null) {
    ps.close();
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
  1. 用户自定义需要存储数据的表名,以及列名。标记列名是为了方便我们对数据的理解。实际上,我们取值的时候只需要根据表的行号以及列号进行取值就可以。
    下面的这个类是一个工具类,用来生成在数据库中需要执行的sql语句。实现自动化处理。这里要求在为列取名字的时候尽量使用英文,因为中文可能会出现编码格式不一样的问题。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class DataBaseTool {
//根据用户定义的 数据库的表名,列名 来创建一个基本的数据库 (名称要选取英文字母)
public String createDataBase(List<String> lie) {
String sql = "CREATE TABLE ";
//计算列的长度并遍历
if(lie.size()!=0) {
sql+=(lie.get(0)+"( ");
for(int i =1;i<lie.size()-1;i++) {
sql+=(lie.get(i)+" VARCHAR(50),");
}
sql+=(lie.get(lie.size()-1)+" VARCHAR(50));");
}else {
return null;
}
return sql;
}
// 往数据库中插入数据 数据库的表名 返回插入数据的sql语句
public String InsertData(List<String> lie){
String sql = "INSERT INTO "+lie.get(0)+"(";
String valueString = "";
if(lie.size()!=0) {
int len = lie.size();
for(int i=1;i<len-1;i++) {
sql+=(lie.get(i)+",");
valueString+="?,";
}
sql+=(lie.get(len-1)+") value("+valueString+"?);");

}else {
return null;
}
return sql;
}
}
  1. 最后,我们要执行的是将我们缓存在系统中的数据存储在我们自定义的数据库中,保存成统一的格式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class BaseOperate {
DataBaseTool tool = new DataBaseTool();
Connection conn = null;
PreparedStatement ps = null;
Result rs = null;
//根据相关数据在数据库中,创建一个数据表,用来存储数据
public void createTable(List<String> lie) {
String sql = tool.createDataBase(lie);
try {
JdbcUtils.getQueryRunner().update(sql);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//批量导入数据到数据表中
public void INSERTDate(List<String> lie) {
FileRead toolFileRead = new FileRead();
List<List<String>> mapList = toolFileRead.readFILE();
String sql = tool.InsertData(lie);
conn = JdbcUtils.getConnection();
try {
//设置不自动提交执行
conn.setAutoCommit(false);
ps = conn.prepareStatement(sql);
for (int i = 0; i < mapList.size(); i++) {
for(int j = 0;j<mapList.get(0).size();j++) {
ps.setString(j+1,mapList.get(i).get(j));
}
ps.addBatch();
}
int[] a = ps.executeBatch();
ps.clearBatch();
conn.commit();
System.out.println(a.length);
} catch (SQLException e) {
// TODO Auto-generated catch block
try {
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}finally {
JdbcUtils.close(conn, ps);
}
}
}

4、实现的效果为下图所示,这样我们就可以对数据的每一行或者每一列进行分析,,更加直观,可以只关注我们要关注的那部分:
在这里插入图片描述

轨迹图(一)

引用百度API并建立密钥

我们这里因为用的是百度地图提供的服务,因此,使用的开发文档是百度的API,这里面集成了大量的与地图相关的服务。这个是开源的,免费的。但是想要使用的话,是需要在百度地图控制台申请一个本机的密钥。

1
<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=密钥"></script>

引入相关js 文件

只有百度提供的API是不够的,还需要一些依赖包去满足更多的需求。

1
2
3
<script type="text/javascript" src="js/echarts3.8.5.min.js"></script>
<script type="text/javascript" src="js/bmap3.8.5.min.js"></script>
<script type="text/javascript" src="js/jquery.min.js"></script>

如果是需要对地图有更多的要求,或者只是单纯对某一个地区进行操作,则需要引用其他的的js文件。

建立一个盒子接收

因为我们的地图是基于Html 进行的,因此需要一个div对获得数据进行接收。这里直接创建一个带有id属性的div即可。

1
<div id="allmap"></div>

编写JS文件

获得盒子

这里就是获得我们刚刚创建的div ,用来接收地图。

1
var myChart = echarts.init(document.getElementById('allmap'));

设置属性

接下来是对地图样式的设置,这里的内容是比较多的,也是需要后期继续学习与研究的,这里先简单的介绍一些比较简单的。

1
2
3
4
5
6
var bmap = {
center: [startPoint.x, startPoint.y],
zoom: 15,
roam: true,
mapStyle: {}
}

上面为我们的地图样式提供了一个框架,第一个参数是我们第一次访问地图时候显示的中心位置,第二个参数是地图放大多少,第三个参数是指我们是否有权限自己调节大小,这里我们主要设置的是mapStyle的内容,也就是地图的样式,下面是几个实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
styleJson: [
{
'featureType': 'land', //调整土地颜色
'elementType': 'geometry',
'stylers': {
'color': '#081734'
}
},
{
'featureType': 'building', //调整建筑物颜色
'elementType': 'geometry',
'stylers': {
'color': '#04406F'
}
},
{
'featureType': 'building', //调整建筑物标签是否可视
'elementType': 'labels',
'stylers': {
'visibility': 'on'
}
},
{
'featureType': 'highway', //调整高速道路颜色
'elementType': 'geometry',
'stylers': {
'color': '#015B99'
}
},
{
'featureType': 'highway', //调整高速名字是否可视
'elementType': 'labels',
'stylers': {
'visibility': 'off'
}
]

显示数据

最后,我们调整完所有的参数之后,读取一下我们的数据集,保存在一个列表里面,我们这里用series来表示。将我们的数据,设置到option里面。

1
2
3
4
5
6
option = {
bmap: bmap,
zoom: 13,
color: ['gold', 'aqua', 'lime'],
series: series3
};

最后调用函数,使用指定的配置项以及数据将地图显示出来。

1
myChart.setOption(option);

效果图

这里随便选取了家乡的几个点,作为测试,效果图如下:
在这里插入图片描述

阿里云+Ubuntu+Mysql

整个过程虽然不是很复杂,但是在这个过程中所学到的知识以及对自己的反思感觉还是有必要记录一下的。

安装

对于mysql 在linux系统上的安装过程,在自己的[CSDN博客](https://blog.csdn.net/qq_39536716/article/details/106906228) 中已经有所总结与介绍,比较简单这里就不多说了,到此为止在linux上登陆并使用mysql是没有什么问题了。主要是聊一聊下面的过程。

防火墙

我们在进行远程连接的时候,一般Linux上都有防火墙设置,阻止外界直接访问系统端口。

1、可以通过测试:
telnet xxx.xxx.xxx.xxx 端口号
进行测试。
这时候我们可以发现telnet 是不通过的,3306端口拒绝访问。
2、在linux界面进行端口监测,查看3306端口是否已经开启访问:

1
sudo ufw status

这行命令显示出系统已经开启的端口访问。
如果显示有3306 端口 ALLOW 表示防火墙允许远程主机访问。

3、如果未显示上述结果,则需要开放防火墙端口

1
sudo ufw allow 3306

然后在查看防火墙的端口设置,最后重启防火墙

1
sudo ufw reload

配置文件

经过上述配置之后,我们远程电脑与linux 系统的3306端口已经打开第一道防线,一般mysql 的配置中还会对3306端口进行监听。
我们通过下面的命令来查看是否有监听:

1
netstat -an | grep 3306

如果结果中有对127.0.0.1 的监听,表示3306这个端口目前只能被本机使用,因此我们就要修改一下mysql的配置文件。
这一部分在网上查的是在/etc/mysql/my.cnf ,此时我们可以进去可以看到:

1
2
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/

这个文件的意思是表示包含/etc/mysql/conf.d/这个路径下面的配置文件,前提是必须以.cnf为后缀,第二行同理;
在这个配置文件这里花费的时间是最长的,因为在找bind-address 的时候花费的时间是最多的。当理解上面的两行命令之后,就可以直接去到conf.d 与 mysql.conf.d中去找,这两个文件夹里面依旧是有配置文件的。

网上对这两个配置文件的描述大多数也比较模糊,通过vim查看刚开始没有找到,注意我这里是直接通过眼睛观察的(有点可笑),并且在查看mysqld.cnf的时候没有发现bind-address这个关键字(具体的原因是因为我没有进行翻页,这是后来才发现的)。苦苦找了一个多小时,无果。
于是死马当作活马医,就使用了

1
vim /etc/mysql/mysql.conf.d/mysqld.cnf | grep bind-address

没想到奇迹发生了 找到了bind-address
这时候才想起来 翻页这回事(有点傻了)
此时注释掉 bind-address 即可。
重启mysql

阿里云客户端配置

这时候linux上的所有配置以为全部结束,便开始远程登陆,难受的事情又发生了,在一个陌生的ip地址处,拒绝了访问。真是有点小苦恼了。拒绝访问,肯定是在数据请求的过程中又有拦截,之前配置过8080端口,于是就去尝试了一下在阿里云客户端处设置3306的可访问操作。
这里在客户端的安全组中就可以添加。

创建远程连接

一切全部配置好了,这时候以为终于可以安全的远程登陆mysql了,没想到意外又发生了(想哭)
远程登陆显示ERROR 1130 (HY000) Host ‘xxxxx’ is not allowed to connect to this Mysql server.
一个陌生的错误出现了,于是在网上查了查这个错误的原因。
这个错误是典型的远程权限问题,远程电脑没有足够的权限对linux上的软件进行访问,于是是需要登陆mysql进行创建一个远程登陆用的账户:

1
grant all PRIVILEGES on db_name.* to 'username'@'xxx.xxx.xx.x' identified by 'password' WITH GRANT OPTION

这里的xxx 表示可以远程访问的ip地址,为了能够访问的时候方便一下,我们尽量在设置自己主机IP的时候,不要使用动态连接池。
或者 我们也可以把xxx用% 替代,这时候就表示所有ip的主机都可以进行访问。不过这样数据的安全性就很大的降低了。
最后,为了让我们的配置生效,我们需要执行:

1
FLUSH   PRIVILEGES;

至此,我们就可以成功的连接了。

题目01(单步跟踪)

内存中的情况如下图,写出下面指令执行后的寄存器ax,bx,cx中的值
在这里插入图片描述
ax = 1123
bx = 8833
cx = 8833

题目2

  1. 存放值
    在这里插入图片描述
    -e 1000:0 23 11 22 11
    -r 指令用来显示内存中各个值的情况
    -a 1386:100

-t 为单步跟踪

寄存器(内存控制04)

基本指令示例

(1)将10000H~1000FH 这段空间当作栈,初始状态为空。
mov ax,1000H
mov ss,ax
mov sp,0010H
(2)设置AX=001AH,BX = 001BH;
mov ax,001AH
MOV bx,001BH
(3)将AX,BX中的数据入栈
push ax
push bx
(4)将AX,BX清零
sub ax,ax
sub bx,bx
(5)从栈中恢复AX,BX中的值
pop bx
pop ax

指令执行的过程

执行push的时候,先改变SP(PS=PS-2),然后向SS:SP处传送
执行pop的时候,先读取SS:SP处的数据,然后改变SP(SP=SP+2)。
栈顶的最大变化范围是0~FFFFH

如果我们将10000H~1FFFFH这段空间当作栈段,初始状态是空的,此时,SS=1000和,sp=0010H
任意时刻,SS:sP指向栈顶元素,当栈为空的时候,栈中没有元素,也就不存在栈顶元素,所以SS:SP只能指向栈的
最底部单元下面的单元,该单元的偏移地址为栈最底部的字单元的偏移地址+2,栈最底部的字单元的地址为1000:FFFE,所以,
栈空的时候,SP=0000H

综述

我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元,这些完全是我们自己安排的。
1、数据段将它的段地址放在DS中,用mov、add、sub等访问内存单元的指令的时候,CPU就将我们定义的数据段中的内容当作
数据段来访问。
2、代码段,将它的段地址存放在CS中,将段中第一条指令的偏移地址存放在IP中,这样CPU就将执行我们定义的代码段中的指令。
3、栈段,将他的段地址放在SS中,将栈顶单元的偏移地址放在SP中,这样CPU在需要进行栈操作的时候,比如执行PUSH、POP指令
,就将我们定义的栈段当作栈空间来使用。

寄存器(内存访问02)

mov 指令

mov 寄存器,数据
mov 寄存器,寄存器
mov 寄存器,内存单元
mov 内存单元,寄存器
mov 段寄存器,寄存器
mov 寄存器,段寄存器

数据段

我们可以根据需要将一组内存单元定义为一个段。
我们可以将一组长度为N(N<=64k)、地址连续、起始地址为16的倍数的内存单元当做为专门存储数据的内存空间,从而定义了一个数据段。

mov指令要访问内存单元,可以在mov指令中只给出单元的偏移地址,此时,段地址默认在DS寄存器中。

[add] 表示一个偏移地址为add的内存单元。

在内存和寄存器之间传送字型数据的时候,高地址单元和高8位寄存器、低地址单元和低8位寄存器相对应。

mov、add、sub是具有两个操作对象的指令。jmp是具有一个操作对象的指令。

栈是一种具有特殊的访问方式的存储空间,他的特殊性就在与先进的后出,后进的先出。

栈的两个基本的操作:入栈还有出栈。
8086CPU中提供的入栈还有出栈的操作。
PUSH ax:将寄存器ax中的数据送入栈中。
POP ax: 从栈顶取出数据送入ax中。
8086CPU中的入栈和出栈操作都是以字为单位进行的。

CPU如何指导当前要执行的指令所在的位置?
因为:寄存器CS和IP中存放着当前指令的段地址和偏移地址。

8086CPU中,有两个寄存器;
段寄存器SS 存放栈顶的段地址
寄存器SP 存放栈顶的偏移地址
任意时刻,SS和SP指向栈顶元素。

执行PUS的时候,sp偏移地址-2

pop ax的过程

(1)将SS:SP指向的内存单元处的数据送入ax中
(2)SP = SP+2,SS:SP指向当前的栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。

栈顶越界的问题

SS和SP 只是记录了栈顶的地址,当栈顶越界的时候是非常危险的,栈顶溢出,溢出攻击。

我们既然将一段空间安排为栈,那么在栈空间之外的空间里面很可能是存放有其他用途的数据,代码等。将这些数据,代码意外地改写,将会引发一连串的错误。
CPU可以解决这个问题。

栈与内存

栈空间当然也是内存空间的一部分,它只是一段可以以一种特殊的方式进行访问的内存空间。

PUSH/POP 寄存器dx、段寄存器ds、内存单元[0]

0607

寄存器(内存访问01)

内存中字的存储

在0地址位置开始存放20000(4E20H):
注意:0号单元是低地址,1号单元是高地址。4E会存放在高地址,20会存放在低地址。
结论:任何两个地址连续的内存单元,N号单元和N+1号单元,可以将他们看作是两个内存单元,也可以将他们看作是一个地址为N
的字单元中的高位字节单元和低位字节单元。

DS和[address]

CPU要读取一个内存单元的时候,必须先给出这个内存单元的地址;
在8086PC中,内存地址由段地址和偏移地址组成。
8086CPU中有一个DS寄存器,通常用来存放要访问的数据的段地址。

已经知道的Mov指令可以完成两种传送的功能
(1)将数据直接送入寄存器
(2)将一个寄存器中的内容送入另一个寄存器中。
除此之外,mov指令还可以将一个内存单元中的内容送入一个寄存器中。
mov
mov指令的格式:
mov 寄存器名,内存单元地址
“[…]”表示一个内存单元,“[…]”中的0表示内存单元的偏移地址。
内存中的段地址是多少呢?
1、执行指令的时候,8086CPU自动读取DS中的数据为内存单元的段地址。
如何利用mov指令从10000H中读取数据呢?
1、10000H表示为1000:0(段地址:偏移地址)
2、将段地址1000H放入ds中
3、用MOV al,[0]完成传送(MOv指令中的[]说明操作对象是一个内存单元,[]中的0说明这个内存单元的偏移地址是0 ,他的段地址默认
放在ds中。)
8086CPU不支持将数据直接送入段寄存器的操作,ds是一个段寄存器。要先放入通用寄存器。**

寄存器(CPU的工作原理)

通用寄存器

8086CPU有14个寄存器,他们的名字称为诶:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。
8086CPU所有的寄存器都是16位的,可以存放两个字节。
为了保证兼容性,这四个寄存器都可以分为两个独立的8位寄存器使用。
AX可以分为 AH还有AL; AH还有AL寄存器是可以独立使用的8位寄存器。
BX可以分为BH还有BL;
CX可以分为CH还有CL;
DX可以分为DH还有DL;

字在寄存器中的存储

一个字可以存在一个16位的寄存器中,这个字的高位字节和低位字节自然就存在这个寄存器的高8位寄存器和低8位寄存器中。

几条汇编指令

汇编指令是不区分大小写的
mov AX,BX 的意思是将BX中的数据放在AX中
add AX,BX 的意思是将BX与AX相加,放在AX中

如果超过数据的存储范围,就会有数据的丢失
这里的丢失,指的就是进位制不能在8位寄存器中保存,但是CPU不是真的丢弃这个进位值。

物理地址

CPU访问内存单元的时候要给出内存单元的地址,所有的内存单元构成的存储空间是一个一维的线性空间。
我们将这个唯一的地址称为物理地址。
决定一个CPU是多少位的,有以下三方面的特点

  • 运算器一次最多可以处理16位的数据。
  • 寄存器的最大宽度为16位。
  • 寄存器和运算器之间的通路是16位的。
    8086CPU在读写内存的时候,发生了一些事情:

  • CPU中的相关部件提供两个16位的地址,一个称为段地址,另一称为偏移地址

  • 段地址和偏移地址通过内部总线送入一个称为地址加法器的部件;
  • 地址加法器将两个16位地址合并成一个20位的地址。
    地址加法器合成物理地址的方法:
    物理地址=段地址×16+偏移地址
    

    段的概念

    内存并没有分段,段的划分来自于CPU,由于8086CPU用“段地址*16”+偏移地址=物理地址的方式。实际上,内存并没有划分成一个一个的段。
    以后在编程的时候,根据需要将若干个地址连续的内存单元看作一个段,用段地址X16定位段的起始地址(基础地址),用偏移地址定位段中的内存单元。
    段的起始地址一定是16的倍数。
    偏移地址为16位,所以一个段的长度最大为64k。

    CPU可以用不同的段地址还有偏移地址来形成同一个物理地址。

段寄存器

段寄存器就是用来提供段地址的。8086CPU有4个段寄存器:CS、DS、SS、ES
当8086CPU要访问内存的时候,由这4个段寄存器提供内存单元的段地址。

CS和IP

CS和IP是8086CPU中最关键的寄存器,他们指示了CPU当前要读取的指令的地址。
CS为代码段寄存器。用来存放指令的段地址。
IP为指令指针寄存器。用来存放指令的偏移地址。
转移指令
修改CS、IP的内容不能使用MOV指令,而是通过使用 JMP进行的。
jmp 段地址:偏移地址
功能:用指令中给出的段地址修改CS,偏移地址修改IP
jmp 1000:3 表示CS= 1000,IP=3

代码段

可以将长度为N(N<=64KB)的一组代码,存在一组地址连续、起始地址为16的倍数的内存单元中,这段内存是用来存放代码的,从而定义了一个代码段。
CPU只认被CS:IP指向的内存单元中的内容为指令。

Real wifi

题目

在这里插入图片描述

先用wireshrk 软件

打开之后观察里面的数据信息,发现协议是802.11协议,这个协议wifi以这个协议作为其网络层以下的协议。

aircrack-ng打开

安装aircrack-ng在官网上下载安装包,然后拖动到Linux的桌面上,双击安装
在这里插入图片描述
使用命令行用aircrack打开数据包。
命令:aricrack-ng realwife.pcap
可以查看都ESSID以及加密的类型。题目中 有说wifi的密码比较弱,因此,我们可以使用弱口令字典暴力破解wifi的密码。
命令:ariack-ng - w rokoul.txt realwife.pcap
我们可以获得wifi的密码

现在找到wifi的密码,但是wifi的密码并不是flag
我们还需要进一步的分析
通过ESSID还有wifi的密码解密原来的文件,得到解密后的新的文件
命令:airdecap-ng -e Blue-Whale -p 12345678 realwife.pcap
得到一个新的pcap文件,我们对http流进行追踪,就可以查看到flag.
在这里插入图片描述