月度归档:2019年01月

QRcode二维码的数据格式

来源:http://www.frostsky.com/2012/07/qrcode-data/

QRcode是二维码的一种。QRcode可以存储最多4296个字母数字类型的任意文本。这些文本可以是任何内容,例如,网址、联系信息、电话号码等等,下面会有介绍。

QRcode存储的信息可以被安装有适当软件的光学设备读取。这种设备既可以是专用的QR code读取器也可以是手机。

qrcode frostsky.com二维码可以储存文本信息,但是文本信息可以代表很多的东西,例如二维码可以将URL进行编码,特殊的字符串让解码器知道这是一个URL地址,从而从浏览器打开这个网址。比如右图就是“http://www.frostsky.com”的二维码。

二维码可以保存洞中类型的可操作文本信息,下面将介绍到底二维码可以存储哪些信息。

一、网址URL

二维码最普通的方式就是编译网址,需要注意的是在编译时网址需要有协议,比如“http://”,否则就会被认为是普通的文本详细。 如:http://www.biaodianfu.com/

需要注意的是二维码在编译大写字母是要比编译小写字母更有效,在没有确定你的服务器是否支持大下写通用时,最好不要使用URL大写。

除此之外,针对网址还有数签形式,格式为:MEBKM:TITLE:标点符;URL:http://www.biaodianfu.com/;;

二、E-mail地址

为了识别出来编译的信息为email地址,格式为:MailTO:username@gmail.com ,解码器就或为你创建一个空白邮件。

除此之外还可以添加邮件的内容,具体格式为 MATMSG:TO: username@gmail.com;SUB:Test;BODY:This is a test. ;;

三、手机号码

在编译手机号码的时候,最好是在手机号码前加上国别好号,比如中国就是“+86”,例如:TEL:+8613800138000

除了编译手机号码以外,还可以编译手机短信,具体示例为:SMSTO:+8613800138000:测试短信;

手机彩信与短信的格式一样,具体为:MMSTO:+8613800138000:测试彩信;

四、个人名片

可以使用vCard(http://en.wikipedia.org/wiki/VCard)格式来使用个人名片。

例如:姓名为孙悟空,地址为花果山,电话为13800138000,邮箱为wukong@huaguoshan.com,具体的格式为:

MECARD:N:孙悟空;ADR:花果山;TEL:+8613800138000;Email:wukong@huoguoshan.com;;

五、地理信息

已编译Google西雅图的办公室的经纬度信息为例,维度为40.71872 ,西经73.98905,经纬度精确到单位到100米。具体格式为:GEO:40.71872,-73.98905,100

QRcode 测试:

Google 提供了QRcode的API,输入以下信息到浏览器地址栏:

http://chart.apis.google.com/chart?cht=qr&chs=100×100&chl=http://www.frostsky.com

即可生成一个二维码。

Spark standalone分布式安装

Spark是一个通用的并行计算框架,由UCBerkeley的AMP实验室开发。
Spark和Hadoop有什么不同呢?
Spark是基于map reduce算法实现的分布式计算,拥有Hadoop MapReduce所具有的优点;但不同于MapReduce的是Job中间输出和结果可以保存在内存中,从而不再需要读写HDFS,因此Spark能更好地适用于数据挖掘与机器学习等需要迭代的map reduce的算法。

Spark的适用场景
Spark是基于内存的迭代计算框架,适用于需要多次操作特定数据集的应用场合。需要反复操作的次数越多,所需读取的数据量越大,受益越大,数据量小但是计算密集度较大的场合,受益就相对较小
由于RDD的特性,Spark不适用那种异步细粒度更新状态的应用,例如web服务的存储或者是增量的web爬虫和索引。就是对于那种增量修改的应用模型不适合。
总的来说Spark的适用面比较广泛且比较通用。

一。Spark目前支持多种分布式部署方式

  • Standalone Deploy Mode;
  • Amazon EC2;
  • Apache Mesos;
  • Hadoop YARN。

第一种方式是单独部署,不需要有依赖的资源管理器,其它三种都需要将spark部署到对应的资源管理器上。

除了部署的多种方式之外,较新版本的Spark支持多种hadoop平台,比如从0.8.1版本开始分别支持Hadoop 1 (HDP1, CDH3)、CDH4、Hadoop 2 (HDP2, CDH5)。目前Cloudera公司的CDH5在用CM安装时,可直接选择Spark服务进行安装。

https://spark.apache.org/docs/latest/spark-standalone.html

二。 以1.0.0版本,来看看如何实现Spark分布式集群的安装:

一、Spark 1.0.0需要JDK1.6或更高版本,我们这里采用jdk 1.6.0_31;

二、Spark 1.0.0需要Scala 2.10或更高版本,我们这里采用scala 2.10.3;

三、从https://spark.apache.org/downloads.html 下载合适的bin包来安装,我们这里选择CDH4版本的spark-1.0.0-bin-cdh4.tgz;下载到tongjihadoop165上;

四、解压bin包:tar –zxf spark-1.0.0-bin-cdh4.tgz;

五、重命名:mv spark-1.0.0-bin-cdh4 spark-1.0.0-cdh4;

六、cd spark-1.0.0-cdh4 ;

  mv ./conf/spark-env.sh.template ./conf/spark-env.sh

七、vi ./conf/spark-env.sh 添加以下内容:

export SCALA_HOME=/usr/lib/scala-2.10.3

export JAVA_HOME=/usr/java/jdk1.6.0_31

export SPARK_MASTER_IP=10.32.21.165

export SPARK_WORKER_INSTANCES=3

export SPARK_MASTER_PORT=8070

export SPARK_MASTER_WEBUI_PORT=8090

export SPARK_WORKER_PORT=8092

export SPARK_WORKER_MEMORY=5000m

SPARK_MASTER_IP这个指的是master的IP地址;SPARK_MASTER_PORT这个是master端 口;SPARK_MASTER_WEBUI_PORT这个是查看集群运行情况的WEB UI的端口号;SPARK_WORKER_PORT这是各个worker的端口    号;SPARK_WORKER_MEMORY这个配置每个 worker的运行内存。

八、vi ./conf/ slaves  每行一个worker的主机名,内容如下:

10.32.21.165

10.32.21.166

10.32.21.167

九、(可选) 设置 SPARK_HOME 环境变量,并将 SPARK_HOME/bin 加入 PATH:

vi /etc/profile ,添加内容如下:

export SPARK_HOME=/usr/lib/spark-1.0.0-cdh4

export PATH=$SPARK_HOME/bin:$PATH

十、将tongjihadoop165上的spark复制到tongjihadoop166和tongjihadoop167上:

sudo scp -r hadoop@10.32.21.165:/usr/lib/spark-1.0.0-cdh4  /usr/lib

安装scala时也可以这样远程拷贝文件并修改环境变量文件/etc/profile,改完之后别忘了source。

十一、执行   ./sbin/start-all.sh    启动spark集群;

如果start-all方式无法正常启动相关的进程,可以在$SPARK_HOME/logs目录下查看相关的错误信息。其实,你还可以像Hadoop一样单独启动相关的进程,在master节点上运行下面的命令:

在Master上执行:./sbin/start-master.sh

在Worker上执行:./sbin/start-slave.sh 3 spark://10.32.21.165:8070 --webui-port 8090

十二、检查进程是否启动,执行jps命令,可以看到Worker进程或者Master进程。然后可以在WEB UI上查看http://tongjihadoop165:8090/可以看到所有的work 节点,以及他们的 CPU 个数和内存等信息。

十三、Local模式运行demo

比如:./bin/run-example SparkLR 2 local   或者  ./bin/run-example SparkPi 2 local

这两个例子前者是计算线性回归,迭代计算;后者是计算圆周率

十四、启动交互式模式:./bin/spark-shell --master spark://10.32.21.165:8070 , 如果在conf/spark-env.sh中配置了MASTER(加上一句export MASTER=spark://${SPARK_MASTER_IP}:${SPARK_MASTER_PORT}),就可以直接用  ./bin/spark-shell启动了。

spark-shell作为应用程序,是将提交作业给spark集群,然后spark集群分配到具体的worker来处理,worker在处理作业的时候会读取本地文件。

这个shell是修改了的scala shell,打开一个这样的shell会在WEB UI中可以看到一个正在运行的Application,如下图: \

最下面的是运行完成的Applications,workers列表是集群的节点列表。

我们可以在这个打开的shell下对HDFS上的数据做一些计算,在shell中依次输入:

A、val file = sc.textFile('hdfs://10.32.21.165:8020/1639.sta')  #这是加载HDFS中的文件

B、file.map(_.size).reduce(_+_)         #这是计算文件中的字符个数

运行情况,如下图:

\

最终结果可以看出有346658513个字符。速度非常快用时不到3s。

或者B阶段执行val count = file.flatMap(line => line.split(' ')).map(word => (word, 1)).reduceByKey(_+_) 和count.saveAsTextFile('hdfs://10.32.21.165:8020/spark') 将计算结果存储到HDFS上的/spark目录下。

也可以执行./bin/spark-shell --master local[2] ,启动一个本地shell ,[2]可以指定线程数,默认是1。

执行exit可以退出shell。

十五、执行   ./sbin/stop-all.sh   停止spark集群

也可以通过单独的进程的stop脚本终止

注意:三台机器spark所在目录必须一致,因为master会登陆到worker上执行命令,master认为workerspark路径与自己一样。

从锦囊妙计想到的28–程序的空间和时间

前面已经说了很多程序上的事情, 今天会引入一个程序中的两个概念, 这两个概念是非常重要的事情!

1. 程序的空间,    通常是指程序  运行时的 占用空间, 最通俗的说 就是占用内存的情况, 当然也有占用磁盘的空间的情况, 但是考虑到磁盘 空间都比较大, 不会太紧张因此, 空间通常指  内存。  另外若是您到了开发大数据的级别那么磁盘空间就要考虑了, 原因是磁盘空间会有空间同时还有访问时间的问题。

2. 程序的时间, 通常是指  程序运行时  需要的时间, 或者花费的时间。   其实后面还有一个 开发时间, 也就是开发效率的问题。  今天就不说明了。

一。 程序空间和时间的意义

举个例子, 大家都熟悉房地产了, 那么在相同面积上盖的楼越多, 最后能卖出的价格就越多, 这么就是为什么都盖高层的缘故了。

类似的, 若是 卖出的价格相同,   占用的面积越小, 越有意义是吧。

程序也是, 就是实现相同功能的情况下, 需要的内存越少, 那么整个计算机就有能力做更多的工作。

在早期的计算机 内存是k的, 有个几百个kb就很多, 后来内存多少M, 也很可怜, 现在尽管是多少G了, 但是计算机的任务也越多了, 需要的内存也越大了。

因此内存占用还是要考虑的。  但不用像以前那么斤斤计较了。

举个例子, 有两个人早上上班没吃早饭, 他们来到了一个煎饼果子面前, 甲去买了一份煎饼果子吃了,用了5元钱, 很高兴, 真便宜。 然后乙也去吃了一份一样的, 画了2元钱。 那么那个更合算?

都知道答案。

明确一下:

程序的空间 通常是指 程序运行时 占用的 内存空间

程序的时间 通常是指 程序运行时  消耗的时间

二。 使用二维数组进行缓存的内存占用情况分析

1. 如下图, 我们要输出如下图形的数据, 看看如何解决

图上图, 这个图形同前面采用二维数组作为辅助对象存储数据, 然后进行分布处理,最后输出是一样的道理

具体实现就不写了。

2. 分析一下二维数组实现的优劣

优点:   二维数组实现简单高效

缺点:  在数组非常大时, 有浪费空间的情况

声明数组如下:

char[][]   tmpBuffer = new char[12][12];

由于二维数组中每行的长度必须相同

具体情况如下:

从上图中 可以看到绿色部分的数据 是浪费的, 因此我们若是采用多个 一维数组, 没个数组长度不同, 然后在把这些一维数组串接到一起就方便了。

用上面的办法进行了多个临时缓存的设置, 那么如何把这些a1,a2, a3, a4 ... 都串联到一起?

3. 用链表 连接不同的对象到一起

什么是链表? 就是用一条链把一些列的东西连接起来, 让这些东西可以从开头一个一个的找到最后的一个东西, 如下图

上图最开始是我们刚开始的a1缓冲区, 然后是a2, 然后是a3, 最后是a12

 三。java实现图形打印

1. 启动eclipse软件, 创建java项目

2. 编写相关函数

参考源代码如下:

import java.util.LinkedList;
public class MyListTuXing {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//System.out.println("采用list做临时图形输出");
		shuChuTuXing(12, 4, 7, 3);
	}
	/**
	 * 这个函数 负责输出具体的 图形
	 * @param lineCount    三角形的行数, 每一行有一个 同行数相同的*
	 */
	public static void shuChuTuXing(int lineCount, int left, int top, int line)
	{
		// 生命一个 list 对象,  用来 存储没一行的 的缓存
		LinkedList< object > tmpBuffer = new LinkedList< object >();

		// 循环 处理每一行
		for(int i = 0; i < lineCount; i++)
		{
			// 声明一个行的缓存区
			char[] tmpLineBuffer = new char[i+1];

			// 处理一行
			shuChuLineTuXing(tmpLineBuffer, i+1);

			// 把处理好的  这一行数据 添加到 链表中
			tmpBuffer.add(tmpLineBuffer);
		}

		// 这个是 输出空白图形的函数,  若是在输出 空白时, 有问题, 应该在这个函数里面
		shuChuKongBaiXing(tmpBuffer, left, top, line);

		shuAllTuXing(tmpBuffer);

	}
	/**
	 * 在已经有的缓存区中 输出一个 空白的 图形结构
	 * @param list     缓存区列表
	 * @param left     空白开始在左边第几个 位置
	 * @param top      空白开始在 上面开始的第几行
	 * @param lineCount   总计有多少行
	 */
	public static void shuChuKongBaiXing(LinkedList list, int left, int top, int lineCount)
	{
		// 循环处理  每一行
		for(int i = 0; i < lineCount; i++)
		{
			// 获取每一行的 数据
			 object  o = list.get(i + top);
			char[] tmpBuffer = (char[]) o;

			// 输出 每一行的数据
			shuChuKongBaiXingLine(tmpBuffer, left, i+1);
		}
	}
	/**
	 * 输出 每一行的  空白  图形
	 * @param tmpBuffer   临时缓存区
	 * @param left     左边开始的位置
	 * @param Line     第几行
	 */
	public static void shuChuKongBaiXingLine(char[] tmpBuffer, int left, int Line)
	{
		for(int i = 0; i < Line; i++)
		{
			tmpBuffer[left - i] = ' ';
		}
	}
	/**
	 * 输出全部的 图形信息
	 * @param list
	 */
	public static void shuAllTuXing(LinkedList list)
	{
		// 循环输出全部的数据
		for(int i = 0; i < list.size(); i++)
		{
			// 获取当前行, 数据
			 object  o = list.get(i);
			// 做强制类型转换
			char[] lineBuffer = (char[])o;
			// 在这行里面, 做循环 输出每一个  字符
			for(int j = 0; j < i + 1; j++)
			{
				// 输出每个 字符
				System.out.print(lineBuffer[j]);
			}
			// 输出换行
			System.out.println();
		}
	}

	/**
	 * 这个函数输出  每一行的  *
	 * @param buffer           行缓存
	 * @param lineXingCount    第几行, 就是这个行有几个*
	 */
	public static void shuChuLineTuXing(char[] buffer, int lineXingCount)
	{
		for(int i = 0; i < lineXingCount; i++)
		{
			buffer[i] = '*';
		}
	}

}

 

上面代码中, 通过采用     LinkedList<Object> tmpBuffer = new LinkedList<Object>();

方式声明了一个 临时缓存区 , 然后再这个缓存区里面, 把每一行的  缓存数据存储起来, 然后进行统一处理。

通过这个办法可以有效的节省 二维数组的空间浪费的问题。

【二维数组尽管浪费一些空间, 但是运行效率是很快的, 链表在运行效率上无法达到二维数组上, 这里是为了说明链表而做的特定程序, 在真正项目中要 综合考虑两个东西的特点而决定的】

3. 除了采用链表(list)来处理外, 我们还可以采用hashMap来处理

什么是map, hashmap,  其中hashmap是map的一种。 那么什么是map, 如下图

一个map可以由两部分组成 ,一部分是存放“实际东西”的部分, 通常叫做values部分

另一个部分是 存放标签的 部分  通常叫做 keys   注意两个都是复数的

在使用时, 是通过标签, 来找到 实际物体。

就像我们在查字典一样, 通过拼音或者部首找到 具体的解释在哪里。

hashmap是 map的一个具体的 实现。 具体是计算机里面的一个东西, 以后可以慢慢知道, 这里了解map就好。

那么程序中更换为map后情况如下面

HashMap<Integer, Object> tmpBuffer = new HashMap<Integer, Object>();

另外, 相关函数声明中, 需要进行处理一下, 然后就完成了修改。 功能类似 list

具体情况参考 程序的源代码,

【提示】 list 和 map 既然可以替换, 那么是否重复了!!

这里替换是在特定场景下, 离开场景就没意义了。  例如  馒头可以解饿, 猪肉也可以解饿, 那么猪肉和馒头在特定场景下可以替换, 但是当来个吃素的时候, 就只能馒头了。

list和map也是, 他们都是一个容器, 都可以存东西, 但是使用方法不一样,    list是按照 一个链接顺序来找东西的, 首先找到前面的东西, 然后在向后一个一个的找。

map是按照标签来找的, 标签可以是不连续的, 也可以是任意的。

这里之所以可以替换是因为他们 都是采用了行号的  办法来 找东西,正好前后顺序和标签 重复了。

 

程序源代码如下:28-MyList-all2

 

另外程序中出现了  LinkedList<Object>,这个是什么?

这个通俗的说 是泛型, 他的好处, 如下面图

核心就是, 通过程序使用中告诉程序, 我的容器(list, map,还有set等) 里面存储的东西的类型, 这样

开发环境就可以自动帮您检测 您放到容器里面的东西是否是这个类型, 不是这个类型的 他就抱问题, 提示你。

其实泛型技术, 不仅仅对容器有效, 还有其他的地方也有效, 具体的以后可以碰到了在说。

 

相关文章

计算机介绍                                  从锦囊妙计想到的01

流程图(分支结构)介绍          从锦囊妙计想到的02

线程介绍                                     从锦囊妙计想到的03

循环结构介绍                             从锦囊妙计想到的05

流程线程总结                             从锦囊妙计想到的06

cpu和线程定义、开始               从锦囊妙计想到的07

分布式计算                                  从锦囊妙计想到的08

分布式中事件和计数                 从锦囊妙计想到的09

内容总结                                     从锦囊妙计想到的10

数据类型,变量简介                从锦囊妙计想到的11

函数和参数                                从锦囊妙计想到的12

用户交互与数据输入输出       从锦囊妙计想到的13

人机交互界面                            从锦囊妙计想到的15 

过程与对象                                从锦囊妙计想到的16

同步和异步                                从锦囊妙计想到的17

顺序打印                                    从锦囊妙计想到的18

数据输入输出                            从锦囊妙计想到的19

屏幕坐标和打印                        从锦囊妙计想到的20

java函数控制输出                     从锦囊妙计想到的21

逐步细化解决复杂问题           从锦囊妙计想到的22

java入门                                    从锦囊妙计想到的23

java复杂过程分析                   从锦囊妙计想到的25

中间辅助功能解决问题          从锦囊妙计想到的26

叠加操作输出复杂图形          从锦囊妙计想到的27

时间和空间                               从锦囊妙计想到的28

编写边测解决问题                  从锦囊妙计想到的29

让程序动起来                          从锦囊妙计想到的30

程序往复运动                           从锦囊妙计想到的31

 

 

 

什么是 Bluetooth 个人区域网 (PAN)

什么是 Bluetooth 个人区域网 (PAN)

Bluetooth 个人区域网 (PAN) 是一种可让您利用便携式计算机、移动电话和手持设备之间的无线链接创建以太网网络的技术。您可以连接到以下类型的启用 Bluetooth 的设备(这些设备都使用 PAN):个人区域网用户 (PANU) 设备、组式临时网络 (GN) 设备或网络访问点 (NAP) 设备。

下面是有关这些设备中每种设备的功能的详细信息:

  • PANU 设备。 连接到启用 Bluetooth 的 PANU 设备可创建一个包含您的计算机和设备的临时网络。

  • GN 设备。 连接到启用 Bluetooth 的 GN 设备可创建一个包含您的计算机、GN 设备和其他任何与同一 GN 设备连接的 PANU 设备的临时网络。

  • NAP 设备。 连接到启用 Bluetooth 的 NAP 设备可让您将计算机连接到更大的网络,如家庭网络、企业网络或 Internet。

有关详细信息,请参阅连接到 Bluetooth 个人区域网 (PAN)。

注意

  • 有些移动电话或个人数字助理 (PDA) 只能使用拨号网络,有些只能使用 PAN,有些则可使用这两种服务。若要了解您的启用 Bluetooth 的设备可以使用哪些服务,请检查您的设备附随的信息。

  蓝牙技术作为一种小范围无线连接技术,能够在设备间实现方便快捷、灵活安全、低成本、低功耗的数据和语音通信,是目前实现无线个人局域网的 主流技术之一。同时,蓝牙系统以Ad Hoc的方式工作,每个蓝牙设备都可以再网络中实现路由选择的功能,可以形成移动自组网络。蓝牙的特性在许多方面正好符合Ad Hoc和WPAN的概念,显示了其真正的潜力所在。而且,将蓝牙与其他网络相连接可带来更广泛的应用,例如接入互联网、PSTN或公众移动通信网,可以使 用户应用更方便或给用户带来更大的实惠。作为医院有线局域网的补充,蓝牙无线个域网克服了有线网络的弊端,可利用电脑等随时随地进行生命体征数据等的查询 录入,在无线监护方面发挥着重要作用。

本文引用地址:http://www.eepw.com.cn/article/201710/368500.htm  1蓝牙组网机制

  1.1蓝牙个域网的网络特性

作为蓝牙SIG的一个工作组,蓝牙个人区域网工作组的主要目标是定义基于IP的蓝牙个域网应用协议,解决以太网数据包的封装、单个微微网中基于IP的个 人区域网络、主设备的转发以及局域网接入点的问题。蓝牙个人区域网协议描述了2个及多个的蓝牙设备如何组成一个Ad Hoc网络以及如何使用同样的机制通过网络接入点接入远程网络。网络接入点可以是传统的LAN数据接入点,而分组Ad Hoc网络表示的仅是一组相互连接的设备。

分组Ad Hoc网络是一组移动主机的集合,它们可以再无需其他网络硬件或网络设施的支持下组成一个Ad Hoc无线网络。PAN协议更侧重的是由一个蓝牙微微网构成的简单个人Ad Hoc网络。网络中有最多可容纳8个设备,其中一个是主节点,其余是从节点。

蓝牙PAN网络具有以下Ad Hoc网络的共同特点:

(1)独立组网能力

各节点在一定网络构成算法的支持下,可以在很短的时间内自动组成一个独立的网络而无需任何网络设施支持。

(2)多跳路由

节点的发射功率较低,因此覆盖范围有限。相互通信范围之外的节点通信需要经过中间节点的转发,经过多跳实现。

(3)拓扑动态变化

在蓝牙PAN中,某些节点具有移动性,可能随时离开或再次加入网络,也有些节点会随时关闭电源,引起节点和链路数量分布的变化,因此蓝牙PAN的拓扑结构可能随时发生变化。

(特殊的信道特征

收无线信道的冲突、信号衰减、噪声以及信道之间的干扰等影响,蓝牙链路的实际带宽远小于理论带宽,而且动态变化。

(5)节点的局限性

大部分蓝牙节点依靠电池供电,能量受限,而且节点存在移动性、内存小以及处理器处理能力有限等特点,因此有效的减少节点能耗非常重要。

(6)安全性

虽然蓝牙采取了严密的安全机制,但由于Ad Hoc网络特点,蓝牙节点易受到窃听、主动入侵与拒绝服务等网络攻击。

蓝牙PAN还有不同于其他Ad Hoc网络的一些特性:

(1)节点通信范围有限

蓝牙节点有效发射距离一般为几米到几十米,儿IEEE802.11等自组织网络可达到几百米。

(2)移动性相对较小

相比其他Ad Hoc网络设备,蓝牙节点的移动速度和频率较小。

(3)带宽窄

蓝牙通常用做数据、语音与低速率的视频传输等应用,因此带宽较窄,目前蓝牙2.0规范定义的最高带宽也只有3Mbit/s,因此,蓝牙网络带宽的优化是个很重要的发展方向。

  1.2蓝牙网络的拓扑结构

蓝牙系统采用一种灵活的无基站的组网方式,使得一个蓝牙设备可与7个其他的蓝牙设备相连接。蓝牙系统的网络结构的拓扑结构有2种形式:微微网(Piconet)和散射网(Scatternet)。

(1) 微微网

微微网是通过蓝牙技术以 特定方式连接起来的一种微型网络,一个微微网可以只是2台相连的设备,比如一台便携式电脑和一部移动电话,也可以是8台连在一起的设备。在一个微微网中, 所有设备的级别是相同的,具有相同的权限。蓝牙采用自组式组网方式(Ad Hoc),微微网主设备(Master)单元(发起链接的设备)和从设备(Slave)单元构成,有一个主设备单元和最多7个从设备单元,如图1所示。主 设备单元负责提供时钟同步信号和跳频序列,从设备单元一般是受控同步的设备单元,受主设备单元控制。

图1 一个主设备和多达7个从设备组成的微微网

在每个微微网中,用一组伪随机跳频序列来确定79个跳频信道,这个跳频序列对于每个微微网来说是唯一的,由主节点的地址和时钟决定。蓝牙无线信道使用跳 频/时分复用(FH/TDD)方案,信道以625μs时间长度划分时隙,根据微微网主节点的时钟对时隙进行编号,号码从0-(227-1)以227为一个 循环长度,每个时隙对应一个跳频频率,通常跳频速率为1600跳/s。主节点只在偶数时隙开始传送信息,从节点只在奇数时隙开始传送,信息包的开始与时隙 的开始相对应。微微网中信道的特性完全由主节点决定,主节点的蓝牙地址(BD_ADDR)决定跳频序列和信道接入码,主节点的系统时钟决定跳频序列的相位 和时间。根据蓝牙节点的平等性,任何一个设备都可以成为网络中的主节点,而且主、从节点可转换角色。

主节点通过轮询从节点实现两者之间 的通信。从节点只有收到主节点的的信息包方可发送数据。如图2,从节点2在t时刻收到来自主节点的数据包,此时频率为f(k),之后它可以在下一个时隙通 过f(k+1)频率向主节点发送数据包。同理,从节点1在t2时刻收到主节点的数据包,此时频率为f(k+2),并且在时间t3通过频率f(k+3)发送 数据包给主节点。

图2微微网内通信轮询机制

(2)散射网

一个微微网最多只能有7个从节点同时处于通信状态。为了能容纳更多的

装置,并且扩大网络通讯范围,多个微微网互连在一起,就构成了蓝牙自组织网,

即散射网,图3。在散射网中,不同微微网间使用不同的跳频序列,因此,只要彼此没有同时跳跃到同一频道上,即便有多组资料流同时传送也不会造成干扰。连 接微微网之间的串连装置角色称为桥(Bridge)。桥节点可以是所有所属微微网中的Slave角色,这样的Bridge的类别为 Slave/Slave(S/S);也可以是在其中某一所属的微微网中当Master,在其他微微网中当Slave,这样的Bridge类别为 Master/Slave(M/S)。桥节点通过不同时隙在不同的微微网之间的转换而实现在跨微微网之间的资料传输。蓝牙独特的组网方式赋予了桥节点强大 的生命力,同时可以有7个移动蓝牙用户通过一个网络节点与因特网相连。它靠跳频顺序识别每个微微网,同一微微网所有用户都与这个跳频顺序同步。

蓝牙散射网是自组网的一种特例。其最大特点是可以无基站支持,每个移动终端的地位是平等的,并可以独立进行分组转发的决策,其建网灵活性、多跳性、拓扑结构动态变化和分布式控制等特点是构建蓝牙散射网的基础。

图3蓝牙散射网实例

  1.3蓝牙散射网拓扑构建的规则

在一个蓝牙WPAN拓扑结构中,主设备或从设备只是节点的一个逻辑状态。一个单元只能是一个微微网的主设备,但可以参与多个相互重叠的微微网。一个主设 备或一个参与多个微微网的活动从设备称为桥;允许微微网构成一个被称为散射网的较大网络。由于使用了跳频技术,一个桥在同一时间不能作为多个微微网的活动 设备;桥必须在一个时分基上的2个微微网间进行转换,转换时必须与当前的微微网再同步,这会带来一个严重影响系统性能的重要开销。

蓝牙WPAN最主要的问题在于构造散射网时遇到由系统规范和通信量需求造成的约束。节点如何组成微微网以及哪个节点作为主设备或桥,对系统的容量、吞吐量和电池的使用时间具有重要影响。

因此,在散列网的构建过程中必须要减少设备间不必要的通信链接以提高网络的吞吐量。每个微微网内设备间的链接是必须的,各微微网内的设备必须要建立通信 链接,以交互信息。因此,冗余通信链接主要在微微网互连阶段。在该阶段中,各微微网之间需要通过桥互连形成蓝牙自组织网。如果两个微微网之间存在过多的 桥,或者一个桥链接多个微微网均会增加冗余通信链接,造成蓝牙自组织网通信性能的下降。通过合理的选桥算法,可以有效降低微微网之间的冗余通信链接。

基于上述分析,我们总结出能够提高散射网性能的组网规则如下:

(1)在蓝牙组网的形成过程中应合理控制微微网的数目,使其限定在一个固定值,以减少微微网之间的通信干扰,保持网络复杂性最小。

(2)减少自组织网内桥节点的负载,防止其成为网络通信的瓶颈。这样不仅能简化桥节点的调度算法,还能缩短因桥节点在不同微微网间切换的而造成的通信传输时延,从而提高网络的性能。

(3)限制设备间的冗余通信链接,尤其是微微网之间的通信链接。通过限制设备间的冗余链接量,可减少设备间的电力消耗,延长网络的使用寿命,还能因减少桥的负载而提高网络的吞吐量。

(在组建蓝牙自组织网的过程中,应优先使用Slave/Slave(S/S)桥,尽量避免使用Master/Slave(M/S)桥,以减少数据包在桥节点上的转发时延,增加蓝牙自组织网的通信量。

(5)网络拓扑形状优良,可以使网络具有自路由功能,从而提高网络的通信能。

 1.4蓝牙散射网拓扑构建的关键问题

蓝牙散射网拓扑构建就是将一组彼此分离的蓝牙节点连接起来,因此蓝牙节点的互相发现过程和节点的角色分配等问题对蓝牙网络的构建以及网络负载均衡影响很大。

(1)蓝牙节点的互相发现

蓝牙节点的互相发现过程是蓝牙散射网拓扑构建过程中的关键部分,在这一过程中,每个蓝牙节点都应该知道它自己通信范围内的节点信息,这个信息应该是对称的,但蓝牙网络中节点数目的不确定性和蓝牙基带规范中节

点连接机制的不对称性给蓝牙节点发现过程的成功实现带来了挑战。

蓝牙规范中规定蓝牙的链接形成由查询(Inquiry)和寻呼(page)两个过程组成,查询过程并没有保证查询节点与被查询节点互相知道对方。欲发现 相邻节点的查询者在发送查询包时,并没有发送它自己的唯一蓝牙识别码,被查询者收到查询包时不知道查询者的信息;另外蓝牙发现机制要求处于相对模式(查询 Inquiry和查询扫描Inquiry scan模式)的两个节点才能互相交换数据,但如何保证两个相邻节点处于相对模式的方法却没有明确规定。这是蓝牙散射网拓扑构建算法应该解决的关键问题。

目前大多数算法采用以下做法:在预定义的节点发现时间长度内,允许每个节点在Inquiry查询模式和Inquiry scan查询扫描模式之间交替变化,每个模式的持续时间在给定的时间范围内是随机的,当两个处于相对模式的节点握手时,他们建立一个临时的微微网。查询者 进入寻呼模式(Page)成为主节点,被查询者进入寻呼扫描(Page scan)模式,成为从节点。两个节点交换他们的ID和下阶段协议需要的信息。信息交换完毕后,微微网就断开。

这样在充足时间内两个相邻节点处于相对模式,从而互相发现的概率值很大。

(2)首领节点的选举过程和方法

因为节点开始时是异步的,还没有其他参与网络构成的节点的相关信息。所以通过选举方式选取首领节点将控制整个网络的构成,获得所有参与构成网络的节点的相关信息,并保证最终形成的散射网是连通的。另外,首领节点的资源应该是丰富的,保证整个网络的健壮性。

(3)各微微网中的主节点的选举

主节点负责维护各个微微网内的节点通信,主节点性能的好坏直接影响该网络的性能。主节点消耗的能量大,因此应该选择能量充分,健壮的节点作为主节点。

(4)桥节点的选择

桥节点对保证蓝牙散射网的连通起着关键性的作用,在网络中,桥节点在同一时刻只能在一个微微网中处于活动状态,它采取时分复用方式在这些微微网间切换, 每切换到一个微微网,就与该微微网同步。桥节点一般分为两类:主桥节点和从桥节点,主桥节点是桥节点在一个微微网中为主节点而在另一个微微网中为从节点, 称为M/S桥。从桥节点是桥节点在两个微微网中都为从节点,称为S/S桥。

蓝牙微微网通过M/S桥连接而形成的蓝牙散射网的拓扑为分级结构,

如图4示:

图4 牙散射网的分级拓扑结构

分级结构中,网络拓扑表现为树形,假设树的根节点所在的微微网为根微微网,其他的微微网为叶微微网,则叶微微网的主节点为根微微网的从节点。各微微网的 内部通信可独立进行,但微微网之间的通信要通过根微微网。因为叶微微网的主节点为桥节点,当它参与根微微网的通信时,所有叶微微网的通信将被挂起,严重降 低了系统的吞吐量。

蓝牙微微网通过S/S桥连接而形成的蓝牙散射网的拓扑为平面结构,如

图5所示:

图5 蓝牙散射网的平面拓扑结构

平面结构中,相邻微微网之间通过共享从节点进行通信,共享的从节点在休眠模式与活动模式之间切换,可以在这些微微网中交替地处于活动状态,实现微微网之间的通信,这种结构是分布式的,利于负载平衡,网络也更健壮。

综上所述,桥节点的选择在保证网络连通性的前提下,还要考虑所连通网络的健壮性,桥节点本身的健壮性也就很关键,因此应选择能量充足的节点作为桥节点; 另外桥节点参与的微微网数量应尽量少,保证网络负载平衡,以及避免桥节点在不同微微网间切换带来的时间延迟和能量消耗。通过以上分析,我们知道只有对以上 几个关键问题有所突破的拓扑构建算法才能构建出连通的,分布式的,时间延迟小的,健壮的蓝牙散射网。

  2蓝牙散射网拓扑构建算法

蓝牙散射网拓扑构建算法就是将一组彼此分离的,对相邻节点信息一无所知的节点连接起来,确定每个节点在网络中的角色,从而形成一个连通的蓝牙散射网。本 节提出的算法可以对微微网数目进行合理控制,并能有效减少微微网间的冗余通信链接,减轻桥设备的负载,从而提高蓝牙散列网的性能。

  2.1主节点的选择

算法采用分布式机制,在组网空间内选出部分权值较高的设备为主节点。每个蓝牙节点都有变量WEIGHT、变量BACK和变量TIMEOUT,其中变量 WEIGHT代表节点的权值(电力等级、剩余能量、数据处理能力等资源状况),这个值表示节点作为主设备的适合度,软件模拟时,每个节点的WEIGHT值 由程序随即设为(1-255)之间的整数;变量BACK代表节点是否需要备份,初始值为0,当节点角色确定为主节点和桥节点时,变量BACK变为1,变量 TIMEOUT为超时设定值。

每个组网蓝牙设备接通电源后周期性切换成Inquiry或Inquiry Scan状态,以发现其他设备或被发现。当两个处于相对模式的蓝牙节点互相发现后,便进行WEIGHT值的比较(相等时,蓝牙地址大的一方获 胜),WEIGHT值较小的一方将已收集到的FHS封包传给WEIGHT值较大的一方,并进入Page scan状态,WEIGHT值较大的一方接收对方的FHS封包后,将其TIMEOUT值复位,继续随机进入Inquiry或Inquiry scan程序;如此一再重复,直到TIMEOUT时间内,都没有再发现任何节点为止(节点会相继进入Page scan,只有处于Inquiry或Inquiry scan状态的节点能相互发现),该节点就是选举出来的主节点,它将进入Page程序,它的变量BACK值变为1,整个程序将进入桥节点的选择阶段。

  2.2.桥节点的选择

各个已选出的主节点根据选桥策略确定互连各微微网的桥节点,并且优先使用权值较高的设备作桥。

由于第一阶段选出的主节点具有所有节点的FHS封包,从而获得需要连接成网的总节点数N总。此时,除了主节点处于Page状态,其余节点均处于Page scan状态,主节点可以通过Page程序与附近节点沟通,主节点运行微微网构成程序(此时,程序first变量的值为0,表示是初始微微网),选择最多 7个节点构成初始微微网,并根据总节点数目的多少和选择weight值较大的从节点为原则,选择其中的最多3个节点作为桥节点。确定为纯从节点角色的节点 同主节点建立连接,进入连接状态,不会再被其它节点搜索到;确定为桥节点角色的节点,会被主节点告知,参与初始微微网后,会再次进入Page scan状态,等待次主节点与之沟通,主节点通过桥节点将次主节点需要的信息传递给次主节点。

因为算法需要为散射网形成以后的每个微微 网中的主节点和桥节点提供一个备份节点,而每个微微网的节点总数为8,除去一个主节点和它的一个备份从节点,还剩6个节点数,为满足备份要求,所以每个微 微网的桥节点数最多为3。选择的桥节点数≤2时,散射网的创建过程是横向展开的,速度较慢,呈线性增长。当桥节点数≥3时,创建过程是全方位展开,速度很 快,呈指数增长。随着桥节点数目的增加,创建过程加快了,但所形成散射网中微微网数量也相应增加了,网间干扰也随之加大了,所以综合考虑,在需要连接的节 点数大于22时,桥节点数量Nb定为3是较好的选择。从节点数Ns尽量为7,具体选择方案如下:

当N总≤8时,Nb=0,Ns=N总-1;

当9≤N总≤15时,Nb=1,Ns=7;

当16≤N总≤22时,Nb=2,Ns=7;

当N总》22时,Nb=3,Ns=7;

初始微微网构成后,并确定桥节点数后,整个程序进入第三阶段。

  2.3组成散射网

每个主节点寻呼各自所发现的设备。通过互连各个微微网,形成蓝牙散列网。

次主节点收到主节点传来的数据后,搜索通信范围内的节点,运行相同的微微网构成程序(程序first变量的值为1,表示生成的为次微微网),因为次主节 点已经与一个桥节点相连,所以此时选择最多6个节点作为从节点,并根据搜索到的节点数目N次总,综合从节点的weight值,选择其中的最多2个从节点作 为桥节点。次微微网的从节点数目Ns′和桥节点数目Nb′的选择方案如下:

当N次总≥8时,选择从节点数目Ns′为6,其中桥节点数目Nb′为2,再选择2个节点为新的次主节点;

当7≤N次总《8时,选择从节点数目Ns′为6,其中桥节点数目Nb′为1,再选择1个节点为新的次主节点;

当N次总≤6时,选择从节点数目Ns′为N次总,其中桥节点数目Nb′为0。

程序结束后,新微微网形成,次主节点成为该微微网的主节点,新的主节点继续选择它的次主节点,新的次主节点同样运行微微网构成程序,微微网的构成过程逐步展开,最后生成一个将所有节点连接起来的散射网。

第二、三阶段程序流程图如图6所示:

图6逐级构建微微网从而构成散射网

散射网构建算法描述如下:其中主节点为N0,微微网构成程序为

Piconet(N0,first),M(u)为次主节点集合,C(v)为第n次产生的次主节点集合。

Scatternet(n,M(u))

if(n=0){

N0=M(u)-{};

First=0;

Return Piconet(N0,first);

else{

M(u)=Scatternet(n-1,M(u));

C(v)={};

while(∣M(u)∣!=0){

u=M(u)-{};

C(v)=C(v)+Piconet(u,first);

M(u)=M(u)-{u};

}

return C(v);

}

}

网络构建过程应尽量向外扩展,所以次主节点的选取应离当前主节点尽量远,可以利用蓝牙中的接收信号强度指示(RSSI)来判断节点之间的距离。RSSI越大表示距离越远。因此,主节点选择RSSI值较大的节点为它的次主节点。

 3.对于算法的节点插入和移除的两个过程

对于一个被给定的蓝牙WPAN拓扑,讨论两种分布式过程来处理拓扑变化。第一个过程是允许在WPAN中插入一个新的节点;第二个过程是从网络中去除一个 节点,这两个过程要达到的主要目标是满足蓝牙规范的限制条件,即全网络连通性,有高的吞吐流量,降低控制信息的开销等。当然,可以加入一个新节点到网络中 去,也意味着可以同时加入几个节点。因此,根据这个,我们可以依靠最初给定的一系列蓝牙设备用来建立一个可增长的BT--WPAN或者形成一个网络拓扑。

(1)插入节点过程

一个节点想快速加入到WPAN中来,它必须首先发送一个普通的查询信息来恳求它附近的节点是否可以加入。相反,如果一个节点的目的是加入到一个网络中并有良好连接,即想加入到具有低流量的微微网中或者扮演一个特殊的角色,它就必须使用专用的查询。

下面部分,讨论承载查询回复的FHS包。注意到,一个数据包FHS它包含有设备类型的标记,加上5比特就能够用于传递未来的信息。这其中2位比特预留下来以备将来使用,AM-ADDR领域的3位在查询回应中不使用。我们定义这5位传送以下信息:

2位:电池的电量等级(如:低于25%,在25%和50%之间,在50%到75%之间,高于75%);

2位:节点的流量的等级;

1位:这个节点是否属于孤立微微网。如果一个微微网没有于任何一个微微网连接或者它附近的微微网都只仅仅与它相连那我们就称之为孤立的微微网。如果该节点属于孤立的微微网,那么该位置1,否则置0。

设a是开始查询过程的节点,正如上所述,根据收到的邻近的节点的回应,a它将决定对哪个节点进行寻呼,回应的节点要么是属于孤立的徽微网要么不属于孤立的微微网。除此之外,它还具有以下可能:

具有少于7个从节点的主节点;

从节点;

即是从节点又是桥节点;

即是主节点又是桥节点;

已经具有7个节点的主节点;

像a一样也在等着加入到蓝牙WPAN中。

a根据以下的优先顺序来选择加入到哪个回应节点;

1)属于孤立的微微网主节点(或者既是主节点又是桥节点的网络节点)

如果a收到不止一个属于孤立微微网的主节点的回应,它将选择从节点少于7个和低流量的的主节点加入。如果不止一个主节点满足上述条件,那么它还根据该节 点的电池电量的等级来考虑。注意到a节点根据相关的RSSI估计每个回应节点的距离。把被选择的主节点记为u,节点a寻呼u并创建一个新的微微网,此时 “a是主节点,u是从节点,过一会儿,这两个节点的角色进行互换,这样,在微微网中,a就变成从节点,并且受主节点u的支配。

如果a收到一个不属于孤立微微网的节点的回应,它将按如下的方式选择:

1)如果回复的是从节点少于7个的主节点(或者既是主节点又是桥节点),则a加入此节点并且创建一个新的微微网。通过主从节点的角色互换,a变成孤立的微微网中的从节点(或者是桥节点)

2)如果回复的节点是从节点(或者既是从节点又是桥节点)或者是具有7个从节点的主节点(或者既是主节点又是桥节点),则“创建一个新的含有该节点的微微网。

2)属于孤立的微微网从节点(或者既是从节点又是桥节点的网络节点)

有两种不同的情况:

1)没有连接到散射网的其它节点回复了a的查询,在这种情况下,a将有以下的情形:

(1)a具有可以成为主节点的足够的处理能力和能t容盘,如果这样,则a通过寻呼一个或多个对它的查询做过响应的从节点来创建一个新的微微网。那么这些 从节点就成了刚形成的微微网和以前微微网之间的桥节点。对于这些被寻呼的从节点,a可以根据其节点的流量、电池状态和空间的距离来选择。假设一个微微网被 一短比特位的字符来标识,即小于5位的长度,并且在微徽网中的每一个节点都知道所在的微微网的标识。一个被a寻呼的从节点可以在承载寻呼响应的FHS包中 利用这’5位来标示这个信息。这样,a随时有可能中断寻呼的过程,因为它连接的节点属于已经有微徽网间连接的节点。

(2)a想成为从节点。a.根据流t,电池等级和空间距离来选择可以加入的节点,它和被选择的节点形成一个新的微微网,然后,在该微微网中,这两个节点互换角色,这样,。就变成了从节点,而被选择的节点则变成了在新微微网和以前微微网之间的主节点和桥节点。

2)a收到一个不属于孤立微微网的的节点的回复。在这种情况下,a试图连接剩余部分散射网中的孤立节点,并且按照以下优先次序在散射网中选择要连接的节 点:从节点、既是从节点又是桥节点的节点、主节点、既是主节点又是桥节点、具有7个从节点的主节点。如果有必要,将依照以下准则进一步进行选择:流量,电 池等级,空间距离。然后,完成要选择的节点后,a创建一个新的微微网。

3、不属于孤立的微微网但是又少于7个从节点的主节点

在现有的可利用的主节点之中,。选择具有最小流量的一个节点,如果在流量相同的情况下,然后考虑电池等级,其次是考虑该节点离a的空间距离。为了避免微 微网之间的重盈和减少微微网内部之间的干扰,离“较近的节点具有优先权。把被选择的主节点记为产,节点a加入声创建一个新的微微网,此处a是主节点,尸是 从节点,过一会儿,这两个节点的角色互换,这样,在微微网中,a变成从节点,并且受主节点产的支配。

不属于孤立的微微网从节点

在2的1)中,介绍了它的两种可能的情况:

1)“具有可以成为主节点的足够的处理能力和能量,如果这样,则a通过寻呼一个或多个响应过它的查询的节点来创建一个新的微微网,同时在新的微微网和以前的微微网中的节点就成为了桥节点。

2)a想成为从节点。在现有的可以利用的节点中选择可以加入的节点,a和被选择的节点形成一个新的微微网,然后,在该微微网中,这两个节点互换角色,这样,a就变成了从节点,而被选择的节点变成了主节点和桥节点。

5、不属于孤立的微微网的既是从节点又是桥节点的网络节点

像前面所说的一样,它也有两种可能的情况:

l)。具有可以成为主节点的足够的处理能力和能量,a依照以下三条准则来选择要寻呼的节点(该节点既是从节点又是桥节点):流量;电池等级;空间距离。这样一个新的微微网形成,此处。作为主节点而被选择的节点作为从节点。

2)a想成为从节点。在这个新的微微网中,a作为从节点,被选择的节点作为主节点而且还充当该微微网与它先前所在的微微网的桥节点。

6、不属于孤立的微微网的既是主节点又是桥节点的网络节点

在现有的可利用的节点(既是主节点又是桥节点)之中,a依照以下三条准则来选择要加入的节点:流量:电池等级:空间距离。在a创建一个新的微微网之后,它与被选择的节点互换一下角色,从而在微微网中a成为从节点并且被它所选择的节点(既是主节点又是桥节点)所支配。

7、不属于孤立的微微网并且已有7个从节点的主节点

在现有的可利用的节点之中,a选择具有最小流量的一个节点,如果在流量相同的情况下,然后考虑电池等级,其次是考虑该节点离“的空间距离。以a为主节点的一个新的微微网被创建了。此时有两种可能性:

1)在这个新的微微网中,a仍然是主节点,而被选择的节点既是从节点又是桥节点;

2)这两个节点互换角色,这样,被选择的主节点使得它的其中的一个从节点处于闲置状态,该闲置节点可以运行插入程序来寻找新的微微网以便加入。要不然,a则和在这个微微网中的其它节点轮流的处于闲置状态。

8、新节点

节点a寻呼到一个新节点,这样创建一个以a为主节点的微微网。然后,如果两个节点协商后,可以互换角色。在该微微网中,同样可以包含一些回应了节点查询 的其它节点。然而,为了保持蓝牙WPAN拓扑的连接性,要么是a要么是它微微网中的其它一些节点必须寻呼现有蓝牙WPAN中节点。

移去节点的过程

节点离开网络引起的变化主要取决于该节点在蓝牙WPAN中作用,有下面四种情况:

。该节点是从节点:该情况最简单,那就是该节点仅仅是从网络中移去,而没有改变拓扑的任何结构。

。该节点是主节点:在该微微网中的从节点将在蓝牙WPAN中寻找一个新的节点来重新建立连接,因此,每一个从节点都要执行插入程序,而桥节点仍然作为桥节点保持与其它微微网的连接。

。该节点既是主节点又是桥节点:这种情况的处理方式与第二种情况的处理方式一样。

。该节点既是从节点又是桥节点:如果有其它节点可以取代该节点,那么它就可从网络中很简单的移去。否则的话,就必须寻找一个可以替代该节点的节点这样, 在此微微网中主节点将执行查询程序,如果不能找到通向目标微微网的桥节点,它将命令它的从节点执行查询程序以寻找桥节点。如果在蓝牙WPAN范围中,在这 些节点所能传输的的范围内没有找到这样的节点,那么该微微网就与蓝牙WPAN断开。

2.射网的重要性能分析

3蓝牙组网的仿真结果和分析

  小结

本章介绍了蓝牙个人区域网络的基本知识,明确了蓝牙微微网和散射网的概念,分析了蓝牙散射网的网路特点,阐述了蓝牙散射网拓扑构建的重要性以及蓝牙散射 网拓扑构建算法需要解决的关键问题和衡量蓝牙散射网拓扑构建算法的标准。蓝牙自组个人区域网络的主从特性、动态性、跳频特性虽然使蓝牙组网更加灵活,但这 些特点以及蓝牙节点本身多为个人数字设备,节点运行的协议和应用程序必须考虑节点处理能力、内存和能耗等条件,都无疑增加了网络拓扑构建 算法、网络路由等算法的难度。

目前蓝牙规范中对微微网内的通信协议有了明确的规定,但对蓝牙散射网的研究,还处于探索阶段,是各国科学 家感兴趣和重点研究的课题之一,越来越多的研究成果完善了蓝牙网络的应用,提高了蓝牙产品的普及率。中国是人口密集,商业经济活动集中、人均收入还比较低 的国家和地区,低成本、组网简单灵活的蓝牙产品将会有更广阔的应用前景。它的应用将遍及很多领域,如移动通信、计算机及周边设备、个人随身信息和娱乐设 备、网络接入设备、医疗保健、金融、军事等。它是面对个人的近距离无线技术,是人与机器之间交流的好助手。

本章从介绍蓝牙节点的工作状 态和蓝牙物理链路的建立过程入手,提出一种备份式的蓝牙散射网拓扑构建算法。算法吸收了Bluestars算法中以节点的可用资源为标准的方法,来选取主 节点,初始主节点建立第一个微微网后,主节点选取最多3个桥节点和3个次主节点,通过逐级展开的方法建立相互连接的微微网,最终形成连通的蓝牙散射网,散 射网形成后通过节点备份的方法,提高网络的自愈能力。本章最后运用数学推导的方法证明了算法几项重要的性能指标为:时间复杂度为O(logN)、消息复杂 度为O(N)、网络直径为O(logN)、具有较少的微微网个数和节点角色的平均数。

参考文章: http://www.eepw.com.cn/article/201710/368500.htm

从锦囊妙计想到的27–多次叠加操作绘制复杂图形

前面26介绍了采用应用中间一个辅助数组的办法, 来辅助缓存中间结果, 然后可以绘制复杂的图形, 今天继续这个话题, 看一个在略微复杂一点的输出

先看一下, 输出的图形

如上图, 若是输出这个图形不采用中间缓存的办法, 直接写, 要写大量的if语句, 并且没办法扩展

若是采用上面26中的方法, 就会简单很多

一。 功能分析

图中输出的图形可以为如下情况

如上图, 可以看到一共有3个图形, 最外面的*号构成的图形, 里面蓝色的由空白构成的三角形

最后是一个红色的小矩形。

这三图形叠加到一起构成了一个完整的图形

二。 实现方法研究

1. 采用主函数启动一个功能函数, 在功能函数里面传入必须的参数进行显示

这样当需要扩展时, 仅仅调整参数就可以扩大或者调整输出

2. 采用二维数组存储中间输出的结果

3. 采用一个专用函数输出最外层的带*的大矩形

4. 采用专用函数在中间的输出结果中输出空白函数的三角形

5.采用函数在前面的中间结果的基础上输出小的空白符号的矩形

6. 最后直接输出中间结果的最终结果到计算机屏幕

参考过程如下

main    {             调用  图形输出                }
                             ||
                            \  / 
                             \/
图形输出{
                      准备二维数组构成的缓存区
                             ||
                            \  / 
                             \/
                      输出最外层的带*的矩形到中间缓存(二维数组中)
                             ||
                            \  / 
                             \/
                      在中间缓存中输出空白图形组成的三角形
                             ||
                            \  / 
                             \/
                      在中间缓存中输出空白图形组成的小矩形
                             ||
                            \  / 
                             \/
                      最后整体将全部图形输出到计算机屏幕上
          }

三。 采用java代码实现上述的功能

1. 启动easyeclipse程序创建一个java的工程

2. 编写程序实现功能

具体代码参考:

public class SanTuXing {

	/**
	 * 输出三个图形叠加的效果
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		// 调用图形输出函数
		TuXing(11, 11);

	}
	/**
	 * 这个函数输出 要打印的图形
	 * @param x    图形的行数
	 * @param y    图形的列数
	 */
	public static void TuXing(int x, int y)
	{
		// 准备一个 临时的缓存区, 系统在初始时, 给每个元素一个默认值了
		char[][]  tmpTuXing = new char[x][y];

		// 输出最外面大的 * 的图形  到 临时缓冲区
		ShuDaDuXing(tmpTuXing, x, y);

		// 输出中间的三角形 到 临时缓冲区
		ShuSanJiaoXing(tmpTuXing, 2, 2, 6);

		// 输出小的矩形到  临时缓冲区
		ShuXiaoJuXing(tmpTuXing, 5, 2, 8, 2);

		// 最后输出全部的数据
		// 优先编写  最后输出的函数, 这样可以检验前面的代码的 正确与否
		ShuChuAll(tmpTuXing, 11, 11);
	}


	/**
	 * 输出中间的小矩形
	 * @param t     缓冲区
	 * @param left  矩形开始的左边
	 * @param top   矩形开始的 上面行数
	 * @param line  矩形有的行数
	 * @param count 矩形每行的个数(空白)
	 */
	public static void ShuXiaoJuXing(char[][] t, int left, int top, int line, int Count){
		for(int i = 0; i < line; i++)
		{
			ShuXiaoJuXingLine(t[i + top], left, Count);
		}
	}

	/**
	 * 输出小矩形的行
	 * @param t     行缓存
	 * @param left  左边开始的
	 * @param Count 每行的个数
	 */
	public static void ShuXiaoJuXingLine(char[] t, int left, int Count){
		for(int i = 0; i < Count; i++)
		{
			t[left + i] = ' ';
		}

	}

	/**
	 * 输出中间的三角形
	 * @param t   缓冲区
	 * @param left  三角形开始的 左边列数
	 * @param top   三级星开始的 上面行数
	 * @param line  三角形有的 行数
	 */
	public static void ShuSanJiaoXing(char[][] t, int left, int top, int line){

		// 输出没一行
		for(int i = 0; i < line; i++)
		{
			ShuSanJiaoXingLine(t[i + top], left, i+1);
		}
	}

	/**
	 * 输出三角形的一行
	 * @param t         行缓存
	 * @param left      开始的左边
	 * @param line      第几行, 其实就是这行的 空白的个数
	 */
	public static void ShuSanJiaoXingLine(char[] t, int left, int line){
		for(int i = 0; i < line; i++)
		{
			t[left + i ] = ' ';
		}
	}

	/**
	 * 输出大的 最外层的矩形
	 * @param t   临时缓冲区
	 * @param x   行数
	 * @param y   每行的  *的个数
	 */
	public static void ShuDaDuXing(char[][] t, int x, int y){
		for(int i = 0; i < x; i++)
		{
			ShuDaDuXingHang(t[i], y);
		}
	}

	/**
	 * 输出 一行的*
	 * @param t   行的缓存
	 * @param y   行的个数
	 */
	public static void ShuDaDuXingHang(char[] t,int y){
		for(int i = 0; i < y; i++)
		{
			t[i] = '*';
		}
	}

	/**
	 *
	 * 输出全部的 符号到计算机屏幕
	 * @param t   缓冲区
	 * @param x   行数
	 * @param y   每行的个数
	 */
	public static void ShuChuAll(char[][] t, int x, int y)
	{
		// 行循环
		for(int i = 0; i < x; i++)
		{
			// 列循环
			for(int j = 0; j < y; j++)
			{
				// 输出行里面的 一个列的数据
				System.out.print(t[i][j]);
			}
			// 这个行完成后, 打印一个换行符号
			System.out.println();
		}
	}

}

 

小结一下

从18开始, 到27, 一直在说图形的输出, 目标是产生直观的输出感觉, 感觉的产生是您写了代码

那么写这个程序的目标是 需要读者理解, 把一个复杂的问题, 划分为若干的简单问题, 然后逐个简单问题处理, 最后在把简单问题整合到一起, 他们共同完成 一个整体的任务。

在写程序中, 我们也一直是这么编写的, 大家参考视频看一下

另外, 今天开始, 其实从26开始, 我们引入了数组的概念, 其实也偷偷的引入了另外的一个东西!

是什么东西, 就是: 数据 和数据处理 或者数据操作

我们化整体为 零散, 然后分零散进行 操作或者完成, 这个过程中, 有一个共同的东西 就是数据

程序一开始就是围着数据的相关处理, 最开始是创建(一种处理), 数据的填充(填充为*), 数据变化(将一部分数据变为空白), 在数据在变换(讲一部分变为空白, 目标是产生小矩形), 最后数据输出(也可以任务是一种操作)

 

相关视频: 链接:https://pan.baidu.com/s/1-oWaw-kPqabYH7ijXCSsGg   提取码:j7av

 

相关文章

计算机介绍                                  从锦囊妙计想到的01

流程图(分支结构)介绍          从锦囊妙计想到的02

线程介绍                                     从锦囊妙计想到的03

循环结构介绍                             从锦囊妙计想到的05

流程线程总结                             从锦囊妙计想到的06

cpu和线程定义、开始               从锦囊妙计想到的07

分布式计算                                  从锦囊妙计想到的08

分布式中事件和计数                 从锦囊妙计想到的09

内容总结                                     从锦囊妙计想到的10

数据类型,变量简介                从锦囊妙计想到的11

函数和参数                                从锦囊妙计想到的12

用户交互与数据输入输出       从锦囊妙计想到的13

人机交互界面                            从锦囊妙计想到的15 

过程与对象                                从锦囊妙计想到的16

同步和异步                                从锦囊妙计想到的17

顺序打印                                    从锦囊妙计想到的18

数据输入输出                            从锦囊妙计想到的19

屏幕坐标和打印                        从锦囊妙计想到的20

java函数控制输出                     从锦囊妙计想到的21

逐步细化解决复杂问题           从锦囊妙计想到的22

java入门                                    从锦囊妙计想到的23

java复杂过程分析                   从锦囊妙计想到的25

中间辅助功能解决问题          从锦囊妙计想到的26

叠加操作输出复杂图形          从锦囊妙计想到的27

时间和空间                               从锦囊妙计想到的28

编写边测解决问题                  从锦囊妙计想到的29

让程序动起来                          从锦囊妙计想到的30

程序往复运动                           从锦囊妙计想到的31