复制粘贴后回放,LR用红字提示:
Action.c(23): Error -27995: Requested link ("Text=发送传真") not found [MsgId: MERR-27995]
Action.c(23): web_link("发送传真") highest severity level was "ERROR", 0 body bytes, 0 header bytes [MsgId: MMSG-26388]
找不到链接?见鬼了!明明有的啊。
重新开一个脚本,另外录制一个再试试:
脚本B
Action() { web_url("mptest", "URL=http://192.168.39.164:8000/mptest/", "Resource=0", "RecContentType=text/html", "Referer=", "Snapshot=t1.inf", "Mode=HTML", LAST); web_link("发送传真", "Text=发送传真", "Snapshot=t2.inf", LAST); return 0; } 回放,OK! 哈哈,小样的,难不倒我。 把脚本B的 web_link("发送传真", "Text=发送传真", "Snapshot=t2.inf", LAST); |
这段脚本copy回原先的脚本A,这总没问题了吧?
点击回放,LR还是提示刚才的错误。咦?这是咋回事?
此路不通,我就反其道而行之。反过来把
web_custom_request("SendFax", "URL=http://192.168.39.164:8000/mptest/SendFax", "Method=POST", "Resource=0", "RecContentType=text/html", "Referer=http://192.168.39.164:8000/mptest/sendFax.jsp", "Snapshot=t3.inf", "Mode=HTML", "EncType=multipart/form-data; boundary=---------------------------7d97d2d7209f6", "BodyBinary=-----------------------------7d97d2d7209f6\r\n" "Content-Disposition: form-data; name=\"address\"\r\n" "\r\n" "05928556088\r\n" "-----------------------------7d97d2d7209f6\r\n" "Content-Disposition: form-data; name=\"senderName\"\r\n" "\r\n" "05928064212\r\n" "-----------------------------7d97d2d7209f6\r\n" "Content-Disposition: form-data; name=\"title\"\r\n" "\r\n" "sfsd\r\n" "-----------------------------7d97d2d7209f6\r\n" "Content-Disposition: form-data; name=\"content\"\r\n" "\r\n" "sfd\r\n" "-----------------------------7d97d2d7209f6\r\n" "Content-Disposition: form-data; name=\"email\"\r\n" "\r\n" "dfd\r\n" "-----------------------------7d97d2d7209f6\r\n" "Content-Disposition: form-data; name=\"pageheader\"\r\n" "\r\n" "sf\r\n" "-----------------------------7d97d2d7209f6\r\n" "Content-Disposition: form-data; name=\"attachment\"; filename=\"C:" "\\x5C" "Documents and Settings" "\\x5C" "Administrator" "\\x5C" "妗岄潰" "\\x5C" "1.txt\"\r\n" "Content-Type: text/plain\r\n" "\r\n" "一、G网测试:\r\n" "SE W810c、Nokia 6120c、Motorola W510、SE W800c\r\n" "二、C网测试:\r\n" "三、回归测试:\r\n" "SE W580i、NOkia n93、Nokia6670(9.9号安排回归测试)\r\n" "Motorola Z3、SE W810c(9.8号安排回归测试)\r\n" "NOKIA5700、Nokia N73(9.5号安排回归测试)\r\n" "\r\n" "\r\n" "*57*号码#\r\n" "*41*号码#\r\n" "#57#\r\n" "\r\n" "0951-8121648\r\n" "\r\n" "-----------------------------7d97d2d7209f6--\r\n" "", LAST); |
这段copy到脚本B中,回放,成功!
不知道大家看明白了没有,整个过程的确是很诡异,我也没搞懂这是为什么,但至少最终还是把问题解决了。有的时候,测试人员千万不要认死理,一条胡同走到黑,遇到问题的时候试试换个角度去解决。
山重水复疑无路,柳暗花明又一村!
LR录制完自动关闭,这个问题似乎有很多人遇到过。其实我一直没有找到真正的原因。不过,没有吃过猪肉不代表没有看过猪跑,没有练过武功不代表不能将你打倒。(这半句是我原创。^_^)
话说多年以前,我曾经写过一个贴子,用一个土办法暂时“解决”了这一问题。具体办法请看下面这个链接:
http://www.blogjava.net/xingcyx/archive/2008/07/16/215190.html
今天,我很不幸地又遇到了同样的问题。有了前面的遭遇,这次我处变不惊,临危不乱,用同样的办法操作了一遍。但是,令我始料不及的是,一种更加诡异的情况出现了!
我的脚本很简单,是一个模拟发送传真的动作,脚本如下:
脚本A
Action() { web_url("mptest", "URL=http://192.168.39.164:8000/mptest/", "Resource=0", "RecContentType=text/html", "Referer=", "Snapshot=t1.inf", "Mode=HTML", LAST); web_link("发送传真", "Text=发送传真", "Snapshot=t2.inf", LAST); lr_think_time( 19 ); web_custom_request("SendFax", "URL=http://192.168.39.164:8000/mptest/SendFax", "Method=POST", "Resource=0", "RecContentType=text/html", "Referer=http://192.168.39.164:8000/mptest/sendFax.jsp", "Snapshot=t3.inf", "Mode=HTML", "EncType=multipart/form-data; boundary=---------------------------7d97d2d7209f6", "BodyBinary=-----------------------------7d97d2d7209f6\r\n" "Content-Disposition: form-data; name=\"address\"\r\n" "\r\n" "05928556088\r\n" "-----------------------------7d97d2d7209f6\r\n" "Content-Disposition: form-data; name=\"senderName\"\r\n" "\r\n" "05928064212\r\n" "-----------------------------7d97d2d7209f6\r\n" "Content-Disposition: form-data; name=\"title\"\r\n" "\r\n" "sfsd\r\n" "-----------------------------7d97d2d7209f6\r\n" "Content-Disposition: form-data; name=\"content\"\r\n" "\r\n" "sfd\r\n" "-----------------------------7d97d2d7209f6\r\n" "Content-Disposition: form-data; name=\"email\"\r\n" "\r\n" "dfd\r\n" "-----------------------------7d97d2d7209f6\r\n" "Content-Disposition: form-data; name=\"pageheader\"\r\n" "\r\n" "sf\r\n" "-----------------------------7d97d2d7209f6\r\n" "Content-Disposition: form-data; name=\"attachment\"; filename=\"C:" "\\x5C" "Documents and Settings" "\\x5C" "Administrator" "\\x5C" "妗岄潰" "\\x5C" "1.txt\"\r\n" "Content-Type: text/plain\r\n" "\r\n" "SE W810c、Nokia 6120c、Motorola W510、SE W800c\r\n" "二、C网测试:\r\n" "三、回归测试:\r\n" "SE W580i、NOkia n93、Nokia6670(9.9号安排回归测试)\r\n" "Motorola Z3、SE W810c(9.8号安排回归测试)\r\n" "NOKIA5700、Nokia N73(9.5号安排回归测试)\r\n" "\r\n" "\r\n" "*57*号码#\r\n" "*41*号码#\r\n" "#57#\r\n" "\r\n" "0951-8121648\r\n" "\r\n" "-----------------------------7d97d2d7209f6--\r\n" "", LAST); return 0; } |
1. MYSQL 编译错误
# cmake . -DCMAKE_INSTALL_PREFIX=/data/mysql/ -DMYSQL_DATADIR=/data/db/mysql_data -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci -DEXTRA_CHARSETS=all -DWITH_SSL=system -DWITH_ZLIB=system -DWITH_EMBEDDED_SERVER=1 -DENABLED_LOCAL_INFILE=1 -DWITH_MYISAM_STORAGE_ENGINE=1 -DSYSCONFDIR=/etc/mysql -DMYSQL_TCP_PORT=3306 -DWITH_DEBUG=0 -DMYSQL_UNIX_ADDR=/tmp/mysqld.sock -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITH_ARCHIVE_STORAGE_ENGINE=1 -DWITH_BLACKHOLE_STORAGE_ENGINE=1 -DWITH_FEDERATED_STORAGE_ENGINE=1 -DWITH_PARTITION_STORAGE_ENGINE=1 -DWITH_SSL=bundled (-DENABLEDONWLAOD=1 -- 如果需要下载一些东西,在此前要保证机器能连接到万维网) |
2. Problem:
“checking for APR... no
configure: error: APR not found . Please read the documentation”
今日编译apache时出错:
#./configure --prefix……检查编辑环境时出现:
checking for APR... no
configure: error: APR not found . Please read the documentation
解决办法:
1.下载所需软件包:
wget http://archive.apache.org/dist/apr/apr-1.4.5.tar.gz wget http://archive.apache.org/dist/apr/apr-util-1.3.12.tar.gz wget http://jaist.dl.sourceforge.net/project/pcre/pcre/8.10/pcre-8.10.zip |
2.编译安装:
yum remove apr-util-devel apr apr-util-mysql apr-docs apr-devel apr-util apr-util-docs
3.具体步骤如下:
a:解决apr not found问题>>>>>>
[root@xt test]# tar -zxf apr-1.4.5.tar.gz [root@xt test]# cd apr-1.4.5 [root@xt apr-1.4.5]# ./configure --prefix=/usr/local/apr [root@xt apr-1.4.5]# make && make install |
b:解决APR-util not found问题>>>>
[root@xt test]# tar -zxf apr-util-1.3.12.tar.gz [root@xt test]# cd apr-util-1.3.12 [root@xt apr-util-1.3.12]# ./configure --prefix=/usr/local/apr-util -with- apr=/usr/local/apr/bin/apr-1-config [root@xt apr-util-1.3.12]# make && make install |
c:解决pcre问题>>>>>>>>>
[root@xt test]#unzip -o pcre-8.10.zip [root@xt test]#cd pcre-8.10 [root@xt pcre-8.10]#./configure --prefix=/usr/local/pcre [root@xt pcre-8.10]#make && make install |
4.最后编译Apache时加上:
--with-apr=/usr/local/apr \ --with-apr-util=/usr/local/apr-util/ \ --with-pcre=/usr/local/pcre |
成功编译完成~
3. Start apache 遇到问题 - httpd: Could not reliably determine the server's fully qualified domain name
启动apache遇到错误:httpd: Could not reliably determine the server's fully qualified domain name
[root@server httpd-2.2.4]# /usr/local/apache/bin/apachectl start
httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName
1)进入apache的安装目录:(视个人安装情况而不同) [root@server ~]# cd /usr/local/apache/conf
2)编辑httpd.conf文件,搜索"#ServerName",添加ServerName localhost:80
[root@server conf]# ls extra httpd.conf magic mime.types original [root@server conf]# vi httpd.conf #ServerName www.example.com:80 ServerName localhost:80 |
3)再重新启动apache 即可。
[root@server ~]# /usr/local/apache/bin/apachectl restart
4. 编译apahce时出错,缺少 apr,apr-util,prce。
完成#3配置后,要编译一下apache,命令如下
./configure \ --prefix=/data/apache2 \ --enable-so \ --enable-rewrite \ --enable-vhost-alias=shared \ --enable-cache=shared \ --enable-file-cache=shared \ --enable-disk-cache=shared \ --enable-mem-cache=shared \ --enable-proxy=shared \ --enable-proxy-http=shared \ --enable-proxy-ajp=shared \ --enable-proxy-balancer=shared \ --enable-proxy-connect=shared \ --enable-dav --enable-dav-fs \ --disable-proxy-ftp \ --disable-userdir \ --disable-asis \ --enable-ssl \ --with-mpm=worker \ --with-apr=/usr/local/apr \ --with-apr-util=/usr/local/apr-util/ \ --with-pcre=/usr/local/pcre |
5. 在安装perl模板遇到问题:
第一次运行 -- “/usr/bin/perl install-module.pl –all”
会遇到 -- can not find install-module.pl 问题。
如何解决?
当运行完 -- ./checksetup.pl 完后,再次运行 /usr/bin/perl install-module.pl –all。
6. #指定Bugzilla的访问目录
<Directory /data/apache2/htdocs/bugzilla> AddHandler cgi-script .cgi Options +Indexes +ExecCGI DirectoryIndex index.cgi AllowOverride Limit FileInfo Indexes </Directory> |
7. 访问http://servername/bugzilla/index.cgi是遇到 500 internal server error的问题
解决方法是,查看 bugzilla官网安装介绍 2.2.4.1.1. Apache httpd? with mod_cgi 发现指定的bugzilla路径的配置与自己有不一样
<Directory /var/www/html/bugzilla> AddHandler cgi-script .cgi Options +ExecCGI DirectoryIndex index.cgi index.html AllowOverride Limit FileInfo Indexes Options </Directory> |
然后我就把#6的配置改下列信息后,就能访问http://servername/bugzilla/index.cgi
<Directory /data/apache2/htdocs/bugzilla> AddHandler cgi-script .cgi Options +ExecCGI DirectoryIndex index.cgi index.html AllowOverride Limit FileInfo Indexes Options </Directory> |
首先需要导入jar包,mail-1.4.2.jar,然后给出最简单的
java mail发送邮件的代码,SimpleSendMailDemo.java
SimpleSendMailDemo.java
package com.steven.mail; import java.util.Properties; import javax.mail.Address; import javax.mail.Authenticator; import javax.mail.Message; import javax.mail.PasswordAuthentication; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; /** * 最基本的邮件发送代码 * * @author Steven * */ public class SimpleSendMailDemo { public static void main(String[] args) throws Exception { // 创建邮件的发送过程中用到的主机和端口号的属性文件 Properties pro = new Properties(); // 设置邮件发送方的主机地址如果是163邮箱,则为smtp.163.com // 如果是其他的邮箱可以参照http://wenku.baidu.com/link?url=Cf-1ggeW3e7Rm9KWfz47UL7vvkRpPxAKBlYoTSGpnK4hxpJDiQ0A4lRoPDncMlcMIvUpEn6PD0aObgm5zJaM7AOGkRdccSx6HDH2fSWkxIq这个文档 pro.put("mail.smtp.host", "smtp.qq.com"); // 设置发送邮件端口号 pro.put("mail.smtp.port", "25"); // 设置邮件发送需要认证 pro.put("mail.smtp.auth", "true"); // 创建邮件验证信息,即发送邮件的用户名和密码 Authenticator authenticator = new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { // 重写验证方法,填写用户名,密码 return new PasswordAuthentication("songdeitao@qq.com", "123"); } }; // 根据邮件会话 构建一个邮件的session Session sendMailSession = Session .getDefaultInstance(pro, authenticator); // 创建一个邮件消息 Message message = new MimeMessage(sendMailSession); // 创建邮件发送者地址 Address sourceAddress = new InternetAddress("songdeitao@qq.com"); // 将原地址设置到消息的信息中 message.setFrom(sourceAddress); // 创建邮件的接收者地址 Address destAddress = new InternetAddress("songdeitao@163.com"); // 将接收者的地址设置到消息的信息中 message.setRecipient(Message.RecipientType.TO, destAddress); // 设置邮件的主题 message.setSubject("Merry Christmas!"); // 设置邮件的发送内容 message.setText("你好,圣诞节快乐!"); // 可以设置邮件的发送时间(就是对方看邮件发送的时间) // String sendDate = "2013-12-23 17:55:00"; // Date date = new // SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(sendDate); // message.setSentDate(date); // 发送邮件 Transport.send(message); } } |
这个例子是完全没有封装后的源代码,如果进行封装的话,可以考虑将发送的邮箱信息封装成一个邮件信息的类,然后验证可以通过一个类继承Authenticator然后复写方法getPasswordAuthentication(),接着发送的主要业务逻辑可以封装成一个类,这样在使用的时候,就可以通过创建邮件信息,进行验证,通过主要的业务逻辑调用发送邮件。
然后发送的最终效果如下图1所示:
图1
具体的实现封装的代码我将会放到资源中,有需要的话可以进行下载。
mysql数据库的全量备份,包括数据和结构。保存最新的10次备份。
创建备份主目录
mkdir /backup
一:编写脚步文件mysql_backup.sh
#!/bin/sh # mysql_backup.sh: 备份mysql数据信息,并且只保留最新的10份. #数据库用户名 db_user="root" #数据库密码 db_passwd="imsuser" #数据库IP db_host="localhost" #数据库名 db_name="ims" #数据库备份信息保存位置. backup_dir="/backup/mysqldata" #文件保存日期格式 (dd-mm-yyyy) time="$(date +"%d-%m-%Y")" # mysql, mysqldump所在目录,不同的安装会有不同目录 #如果只对数据进行备份,可以不用填写 MYSQL="/usr/local/mysql/bin/mysql" MYSQLDUMP="/usr/local/mysql/bin/mysqldump" MKDIR="/bin/mkdir" RM="/bin/rm" MV="/bin/mv" GZIP="/bin/gzip" #检查备份目录 不存在进行存储主目录创建 test ! -w $backup_dir && $MKDIR "$backup_dir" # 检查备份目录 不存在进行存储副目录创建 test ! -d "$backup_dir/backup.0/" && $MKDIR "$backup_dir/backup.0/" #all_db="$($MYSQL -u $db_user -h $db_host -p$db_passwd -Bse 'show databases')" #for db in $all_db #do $MYSQLDUMP -u $db_user -h $db_host -p$db_passwd $db_name | $GZIP -9 > "$backup_dir/backup.0/$time.$db_name.gz" #done # 删除旧的备份信息 test -d "$backup_dir/backup.10/" && $RM -rf "$backup_dir/backup.10" # rotate backup directory for int in 9 8 7 6 5 4 3 2 1 0 do if(test -d "$backup_dir"/backup."$int") then next_int=`expr $int + 1` $MV "$backup_dir"/backup."$int" "$backup_dir"/backup."$next_int" fi done exit 0; |
二:赋予脚步可执行权限
chmod +x mysql_backup.sh
三:添加定时执行计划
vi /etc/crontab
添加:00 5 * * * root /backup/mysql_backup.sh 每日5点钟备份一次数据库
1.小内核,稳定可靠。
2.需要可装卸、可裁剪,以便能灵活应对各种不同的硬件平台。
3.面向应用,强实时性,可用于各种设备控制当中。
国际上常见的嵌入式操作系统大约有40种左,右如:
Linux、uClinux、WinCE、PalmOS、Symbian、eCos、uCOS-II、VxWorks、pSOS、Nucleus、ThreadX 、Rtems 、QNX、INTEGRITY、OSE、C Executive 。他们基本可以分为两类,一类是面向控制、通信等领域的实时操作系统,如windriver公司的vxworks、isi的psos、qnx系统软件公司的qnx、ati的nucleus等;另一类是面向消费电子产品的非实时操作系统,这类产品包括个人数字助理(pda)、
移动电话、机顶盒、电子书、webphone等,系统有Microsoft的WinCE,3Com的Palm,以及Symbian和
Google的
Android等。
一、VxWorks
VxWorks操作系统是美国WindRiver公司于1983年设计开发的一种嵌入式实时操作系统(RTOS),是Tornado嵌入式开发环境的关键组成部分。良好的持续发展能力、高性能的内核以及友好的用户开发环境,在嵌人式实时操作系统领域逐渐占据一席之地。
VxWorks具有可裁剪微内核结构;高效的任务管理;灵活的任务间通讯;微秒级的中断处理;支持POSIX 1003.1b实时扩展标准;支持多种物理介质及标准的、完整的TCP/IP网络协议等。
然而其价格昂贵。由于操作系统本身以及开发环境都是专有的,价格一般都比较高,通常需花费10万元人民币以上才能建起一个可用的开发环境,对每一个应用一般还要另外收取版税。一般不通供源代码,只提供二进制代码。由于它们都是专用操作系统,需要专门的技术人员掌握开发技术和维护,所以软件的开发和维护成本都非常高。支持的硬件数量有限。
Windows CE与Windows系列有较好的兼容性,无疑是Windows CE推广的一大优势。其中WinCE3.0是一种针对小容量、移动式、智能化、32位、了解设备的模块化实时嵌人式操作系统。为建立针对掌上设备、无线设备的动态应用程序和服务提供了一种功能丰富的操作系统平台,它能在多种处理器体系结构上运行,并且通常适用于那些对内存占用空间具有一定限制的设备。它是从整体上为有限资源的平台设计的多线程、完整优先权、多任务的操作系统。它的模块化设计允许它对从掌上电脑到专用的工业控制器的用户电子设备进行定制。操作系统的基本内核需要至少200KB的ROM。由于嵌入式产品的体积、成本等方面有较严格的要求,所以处理器部分占用空间应尽可能的小。系统的可用内存和外存数量也要受限制,而嵌入式操作系统就运行在有限的内存(一般在ROM或快闪存储器)中,因此就对操作系统的规模、效率等提出了较高的要求。从技术角度上讲,Windows CE作为嵌入式操作系统有很多的缺陷:没有开放源代码,使应用开发人员很难实现产品的定制;在效率、功耗方面的表现并不出色,而且和Windows一样占用过的系统内存,运用程序庞大;版权许可费也是厂商不得不考虑的因素。
三、嵌入式Linux
这是嵌入式操作系统的一个新成员,其最大的特点是源代码公开并且遵循GPL协议,在近一年多以来成为研究热点,据IDG预测嵌入式Linux将占未来两年的嵌入式操作系统份额的50%。
由于其源代码公开,人们可以任意修改,以满足自己的应用,并且查错也很容易。遵从GPL,无须为每例应用交纳许可证费。有大量的应用软件可用。其中大部分都遵从GPL,是开放源代码和免费的。可以稍加修改后应用于用户自己的系统。有大量的免费的优秀的开发工具,且都遵从GPL,是开放源代码的。有庞大的开发人员群体。无需专门的人才,只要懂Unix/Linux和C语言即可。随着 Linux在中国的普及,这类人才越来越多。所以软件的开发和维护成本很低。优秀的网络功能,这在Internet时代尤其重要。稳定——这是Linux 本身具备的一个很大优点。内核精悍,运行所需资源少,十分适合嵌入式应用。
支持的硬件数量庞大。嵌入式Linux和普通Linux并无本质区别,PC上用到的硬件嵌入式Linux几乎都支持。而且各种硬件的驱动程序源代码都可以得到,为用户编写自己专有硬件的驱动程序带来很大方便。
四、μC/OS一Ⅱ
五、QNX
由QNX软件公司所开发的QNX操作系统,也是一套类UNIX的嵌入式操作系统,跟VxWorks同样的,QNX也是一套符合POSIX规范的操作系统。
与VxWorks同样发迹于1980年代的QNX,其特殊之处,在于其并非采用传统的高阶硬件虚拟层方式设计,而是以非常细碎的tasks形式来执行,由许多的微核心为基础组成完整的OS服务,因此QNX的硬件设计者可以自由的选择加载执行或不加载某些特定的服务,而不用去变更QNX的核心程序部份。因此基于QNX的嵌入式操作系统可以做到非常小的程度,而且依然可以具有相当高的效率与完整的菜单现。
QNX操作系统核心仅包含了CPU任务排程、进程间通讯、中断重导向以及定时器等部份,而除此之外包含驱动程序、档案系统堆叠协议以及使用者应用程序的所有程序都是属于在使用者阶段执行。QNX操作系统有个相当特殊的Proc阶段,专门负责程序process的建立,以及存储器管理等交集在系统微核心中的组件。基本上,QNX所有的组件都能透过消息传递这个函式来进行沟通,而具有良好定义的通讯机制,也能保障所有的组件都有完全独立且被保护的储存及执行空间。因此有问题的应用程序不会影响到其它组件的稳定性,发生问题的程序将会被自动终止并重新启动。
与传统的操作系统架构相较起来,微核心架构可以让嵌入式系统获得更为快速的平均回覆时间(MTTR),当硬件驱动程序失效,QNX可以在数毫秒之内,就对该驱动程序进行终止、回收资源并重新启动的步骤,让嵌入式设备可接近无停摆时间表现。
不过微核心RTOS的架构除了优点以外,由于其process间的讯息传递功能将会占用存储器频宽,影响到校能表现,因此在实际应用上,就必须采用特殊的最佳化手段,以避免掉讯息传递功能所带来的性能耗损。
虽然QNX整间公司在2004年出售给Haman International Industries,但QNX操作系统的发展脚步依旧没有停止,在国外,除了与各家国际汽车大厂合作,成为车用电子的主力操作系统以外,也获得相当多的航空公司与重要军事单位采用。而在2005年底,QNX也与国内几家包含联电、Zinwell等公司进行了合作,研华、控创等工业计算机厂商也都有针对这方面在发展。
六、Nucleus Plus
这款嵌入式操作系统主要特征就是轻薄短小,其架构上的延展性,可以让Nucleus RTOS所占的储存空间压缩到仅有13K左右,而且Nucleus Plus是一款不需授权费的操作系统,并且提供了原始码。
Nucleus Plus本身只是Acclerated Technology公司完整解决方案里面的其中一环,这个RTOS本身架构属于先占式多工设计,有超过95%的原始码是用标准的ANSI C语言所编写,因此可以非常有效率的移植到各种不同的平台。Nucleus Plus在CISC架构处理器中,核心部份大约占去20KB左右的储存空间,而在RISC处理器上则是40KB左右,核心资料结构仅占约1.5KB,由于其即时回应、先占式多工、以及多process并行,并且开放原始码等特性,在国防、工控、航天工业、铁路、网络、POS、自动化控制以及信息家电等领域广泛受到应用。
就如同QNX一般,Nucleus Plus也可以根据目标产品的需求,来自行剪裁所需要的系统功能,达到精简体积的目的。而配合相对应的编译器(Borland c/c++、Microsoft c/c++)以及动态连结程序库和各种底层驱动程序,在开发上拥有非常相当大的便利性。诸如飞思卡尔(Freescale)、罗技(Logitech)公司、美国NEC、SK Telecom等公司,都有采用Nucleus Plus嵌入式操作系统作为开发产品使用。
七、结束语
在嵌入式应用中,使用实时操作系统(RTOS)是当前嵌入式应用的一个特点,一种趋势,也是单片机应用从低水平向高水平的一个进步。在实际的应用中,根据不同的要求和条件选择合适的操作系统,使开发工作更容易,设计出更完美的嵌入式系统。
μC/OS一Ⅱ是著名的源代码公开的实时内核,是专为嵌入式应用设计的,可用于8位,16位和32位单片机或数字信号处理器(DSP)。它是在原版本μC /OS的基础上做了重大改进与升级,并有了近十年的使用实践,有许多成功应用该实时内核的实例。它的主要特点如下:
公开源代码,容易就能把操作系统移植到各个不同的硬件平台上;
可移植性,绝大部分源代码是用C语言写的,便于移植到其他微处理器上;
可固化;
可裁剪性,有选择的使用需要的系统服务,以减少斗所需的存储空间;
占先式,完全是占先式的实时内核,即总是运行就绪条件下优先级最高的任务;
多任务,可管理64个任务,任务的优先级必须是不同的,不支持时间片轮转调度法;
可确定性,函数调用与服务的执行时间具有其可确定性,不依赖于任务的多少;
实用性和可靠性,成功应用该实时内核的实例,是其实用性和可靠性的最好证据。
Android提供了一个名为SQLiteDatabase的类,该类封装了一些操作
数据库的API,使用该类可以完成对数据进行添加(Create)、查询(Retrieve)、更新(Update)和删除(Delete)操作(这些操作简称为CRUD)
SQLite 目前支持 NULL,INTEGER,REAL(浮点数字),TEXT,BLOB(二进制文本)这5中数据类型。
SQLite 的数据库文件默认位于/data/data/package-name/databases 目录下。
创建一个数据库,首先要实现SQLiteOpenHelper的子类。创建MySqlHelper.java然后让该类实现SQLiteOpenHelper这个抽象类。
package com.alpha.sqlite; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; public class MySqlHelper extends SQLiteOpenHelper { public MySqlHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); // TODO Auto-generated constructor stub } @Override public void onCreate(SQLiteDatabase db) { // TODO Auto-generated method stub //创建一个数据库及表格 3个字段如下 //primary key 字段为主键 主键:表中经常有一个列或列的组合,其值能唯一地标识表中的每一行。这样的一列或多列称为表的主键 db.execSQL("create table mytable(id integer primary key autoincrement,name text,age text)"); } @Override public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) { // TODO Auto-generated method stub } } |
上述代码成功的创建了 SQLiteOpenHelper 的子类 MySqlHelper 然后分别实现了其成员方法 在onCreate方法中 初始化数据库及字段。
private MySqlHelper mysql; private SQLiteDatabase db; mysql=new MySqlHelper(MainActivity.this,"mydb",null,1); db=mysql.getReadableDatabase(); //推荐使用此种方法打开 |
getReadableDatabase()方法创建的数据库首先以读写方式打开数据库,如果用户来存储数据库的磁盘空间已经满了,则会打开失败,然后重新以只读方式打开。
getWritableDatabase()方法创建的数据库首先以读写方式打开数据库,如果用户来存储数据库的磁盘空间已经满了,则会报错。
因此,建议用getReadableDatabase()来创建数据库的实例
向数据库中增加数据:两种方法
第一种用系统提供的API函数添加
ContentValues cv=new ContentValues(); //cv.put("id",1); //id是主键 自增长的 可以不赋值 cv.put("name","上帝"); cv.put("age","27"); db.insert("mytable",null,cv); db.close(); |
第二种方法用数据库语句
db.execSQL("insert into mytable(name,age) values(?,?)",new Object[]{"上帝","27"});
db.close();
两种方法都可以
删除数据两种方法
第一种方法
db.execSQL("delete from mytable where id=2"); //删除id=2的那一行
db.execSQL("delete from mytable where name=?", new Object[]{"上帝"}); //删除符合字段name=上帝的所有行
第二种方法
db.delete("mytable",null,null); //删除数据表里所有的数据
db.delete("mytable","id=?",new String[]{"2"}); //删除数据表mytable中字段 id=2的一整行
修改数据两种方法
第一种方法
db.execSQL("update mytable set name='神',age='23' where id=2"); //注意此处id位 主键 不可修改
//db.execSQL("update mytable set name='艾尼路',age='25' where name=?",new Object[]{"上帝"});
第二种方法
ContentValues cv=new ContentValues(); cv.put("name","艾斯"); cv.put("age","21"); db.update("mytable",cv,"id=?",new String[]{"5"}); |
查询数据库
Cursor cursor=db.query("mytable",new String[]{"id","name","age"},null,null,null,null,null); while(cursor.moveToNext()) //指向下一行 { int idindex=cursor.getColumnIndex("id"); int id=cursor.getInt(idindex); int nameindex=cursor.getColumnIndex("name"); String name=cursor.getString(nameindex); int ageindex=cursor.getColumnIndex("age"); String age=cursor.getString(ageindex); String result=id+" "+name+" "+age; Log.i("result",result); //打印日志 } |
打印的日志如下
所有对数据库的操作最后都要
db.close();
void Main() { int i; char uStr[64]; srand( (unsigned)time( NULL ) );// 最好放在vuser_init里 for (i=0;i<10;i++) { GetUniqueString(i,uStr); lr_output_message(uStr); } } void GetUniqueString(int inValue,char *outStr) { int id, scid; char *vuser_group; lr_whoami(&id, &vuser_group, &scid); web_save_timestamp_param("tStamp", LAST); sprintf(outStr,"%s%05d%010d%04d",lr_eval_string("{tStamp}"),id,rand(),inValue); free(vuser_group); } |
建议把随机种子(srand( (unsigned)time( NULL ) );)放在脚本初始化函数里,只需要初始化一次。若放在子函数里,每次调用都初始化一下的话,产生的随机数可能是一样的。是不安全的代码!这个唯一数,有四关:毫秒级的时间+虚拟用户ID+随机数+传入的参数;基本上在同一个Controller里不会出现重复了!再稍微处理一下就可以得到想法的东西了,譬如:LoadRunner实现:计算字符串Md5 加密成md5串,再改装一下就成GUID了!
这里有一个安全问题值得说明,随机种子最好只初始化一次,随机数的算法是和时间有一定关系的。若把随机种子放在子函数里,你会发现生成出来的随机数都是一样的。
不要惊讶,为什么说是个安全问题,说严重一点,随机数是一种算法,有可能被别人劫获并计算出下一个随机值,故不安全!
LR事务四种状态,在默认情况下使用LR_AUTO来作为事务状态:
1、LR_AUTO
LR_AUTO是指事务的状态有系统自动根据默认规则来判断,结果为PASS/FAIL。
2、LR_PASS
LR_PASS是指事务是以PASS状态通过的,说明该事务正确的完成了,并且记录下对应的时间,这个时间就是指做这件事情所需要消耗的响应时间。
3、LR_FAIL
LR_FAIL是指事务以FAIL状态结束,该事务是一个失败的事务,没有完成事务中脚本应该达到的效果,得到的时间不是正确操作的时间,这个时间在后期的统计中将被独立统计。
4、LR_STOP
LR_STOP将事务以STOP状态停止。事务的PASS和FAIL状态会在场景的对应计数器中记录,包括通过的次数和事务的响应时间,方便后期分析该事务的吞吐量以及响应时间的变化情况。
webdriver提供了丰富的API,有多种定位策略:id,name,css选择器,xpath等,其中css选择器定位元素效率相比xpath要高些,使用id,name属性定位元素是最可靠,效率最高的一种办法。
1、工具选择:在我们开发
测试脚本的过程中各个浏览器给我们也提供了方便定位元素的工具,我比较喜欢使用firefox的firebug工具,也是目前很多开发测试人员比较热衷的选择,原因是firefox是唯一能够集成
selenium IDE的浏览器,并且firebug给用户提供了丰富的扩展组件,我们可以根据自己的需要来选择,一般情况下,使用firebug+firefinder就足够使用了,firefinder支持xpath以及css选择器定位元素的功能,很方便帮助我们调试测试脚本
2、元素定位的方法:findElement() 与 findElements()
findElement() 该方法返回基于指定查询条件的webElement对象,或抛出不符合条件的异常 eg:driver.findElement(By.id("userID"));
findElements() 该方法返回指定查询条件的WebElement的对象集合,或返回null
3、WebElement对象提供的各种定位元素策略
ID:driver.findElement(By.id(<elementID>)) Name:driver.findElement(By.name(<elementName>)) className:driver.findElement(By.className(<elementClassName>)) tagName:driver.findElement(By.tagName(<htmlTagName>)) linkText:driver.findElement(By.linkText(<linkText>)) partialLinkText:driver.findElement(By.partialLinkText(<partialLinkText>)) css:driver.findElement(By.cssSelector(<cssSelector>)) xpath:driver.findElement(By.xpath(<xpathQuery>)) |
4、webelement类提供了诸多方法,在我们开发脚本过程中如何选择最可靠,效率最高的方法,使用id,name是首选,因为他们在html标签中是唯一的,所以是最可靠的
ID定位:driver.findElement(By.id("username"))
name定位:driver.findElement(By.name("username"))
class定位:driver.findElement(By.className("username"))
多学一招:WebElement类支持查询子类元素,如果页面中存在重复元素,但在不同div中,我们可以先定位到其父元素,然后定位其子元素,方法如下:
WebElement hello = driver.findElement(By.id("div1")).findElement(By.lindText("hello"));
5、使用WebElements定位多个相似的元素,比如页面中存在五个单选按钮,他们有相同的class属性,值为:myRadio,我们想对五个按钮循环操作,我们可以把它们全部取出来放到集合中,然后做循环操作,如下:
List<WebElement> radios = driver.findElements(By.className("myRadio")); for(int i = 0;i<radios.size();i++){ radios.get(i).click(); } |
其他定位方法与操作id,name类似,这里不再赘述,接下来我着重对css选择器与Xpath描述下
一、WebDriver 的By类中提供了cssSelector()方法,该方法使用有以下几种形式:
1、使用相对路径定位元素
如,我们要定为DOM中的input元素,我们可以这样操作,不考虑其在DOM中的位置,但这样做存在一定弊端,当DOM中存在多个input元素时,该方法总返回DOM中的第一个元素,这并不是我们所期待的
eg:WebElement username = driver.findElement(By.cssSelector("input"));
另外,为了使用这种方法更准确的定位元素,我们可以结合该元素的其他属性来实现精确定位的目的
a、结合id来定位,driver.findElement(By.cssSelector("input#username")); 在标签与id之间使用#连接,如果对css了解的朋友一看就知道为什么会这样写了,不了解也没关系,只要记住这种写法就OK了
另外该方法也可简写为driver.findElement(By.cssSelector("#username")); 有点儿类似于id选择器
b、使用元素的任何属性来定位元素
driver.findElement(By.cssSelector("标签名[属性名='属性值']"));
c、匹配部分属性值
^= driver.findElement(By.cssSelector("标签名[属性名^='xxx']")); 匹配属性值以xxx开头的元素 $= driver.findElement(By.cssSelector("标签名[属性名$='xxx']")); 匹配属性值以xxx结尾的元素 *= driver.findElement(By.cssSelector("标签名[属性名^='xxx']")); 匹配属性值包含xxx的元素 |
2、使用相对+绝对路径方法,这里是我自己定义的方法,方便记忆,的确也是这样来实现的
driver.findElement(By.cssSelector("div#login>input")) 该方法中“div#login>input” 首先通过相对路径定位到id为login的div元素,然后查找其子元素input(绝对路径)
二、使用xpath定位元素,相比cssSelector,xpath是我比较常用的一种定位元素的方式,因为它很方便,缺点是,消耗系统性能
1、使用绝对路径定位元素
driver.findElement(By.xpath("/html/body/div/form/input"))
2、使用相对路径定位元素
driver.findElement(By.xpath("//input")) 返回查找到的第一个符合条件的元素
3、使用索引定位元素,索引的初始值为1,注意与数组等区分开
driver.findElement(By.xpath("//input[2]")) 返回查找到的第二个符合条件的元素
4、结合属性值来定位元素
driver.findElement(By.xpath("//input[@id='username']"));
driver.findElement(By.xpath("//img[@alt='flowr']"));
5、使用逻辑运算符,结合属性值定位元素,and与or
driver.findElement(By.xpath("//input[@id='username' and @name='userID']"));
6、使用属性名来定位元素
driver.findElement(By.xpath("//input[@button]"))
7、类似于cssSlector,使用部分属性值匹配元素
starts-with() driver.findElement(By.xpath("//input[stars-with(@id,'user')]")) ends-with driver.findElement(By.xpath("//input[ends-with(@id,'name')]")) contains() driver.findElement(By.xpath("//input[contains(@id,"ernam")]")) |
8、使用任意属性值匹配元素
driver.findElement(By.xpath("//input[@*='username']"))
9、使用xpath轴来定位元素
这里略了,详见w3school.com
三、使用innerText定位元素
1、使用cssSelector查找innerText定位元素
driver.findElement(By.cssSelector("span[textContent='新闻']"));
2、使用xpath的text函数
driver.findElement(By.xpath("//span[contains(text(),'hello')]")) 包含匹配
driver.findElement(By.xpath("//span[text()='新闻']")) 绝对匹配
在许多很好的例子,技术和方法被世界上最好的
数据库性能专家所高荐。我们将讨论提高数据库性能的最常用的方法,而不是评论或建议任何特定的工具或技术。
1)谨慎而有效地使用索引
选择合理的索引(前缀性及可选性)、删除没有用的索引。
2)使用规范化,但不要使用过头
规范化(至少是第三范式)是一个易于理解且标准的方法。然而,在有些情况下,你可能希望违反这些规则。查询表通常是规范化的产物,也就是说,你创建了一个特殊的表,这个表包含了在其他表中被频繁使用的相关信息的列表。然而,当使用那些经常被访问且分布有限(仅有或有限的行数拥有小值)的查找表时,会使系统性能降低。在这种情况下,每次你使用查询信息,它们必须使用join以获取完整数据。join的开销很大,而且频繁访问会使开销随着时间逐渐增加。为了减少这种潜在的性能问题,可以使用枚举字段存储数据,而不是使用查找表存储数据。例如,可以使用枚举字段存储头发彩色值,而不是创建表来存储头发颜色值,这样还可以避免使用join.
3)使用正确的存储引擎
mysql的最强大的功能之一是它支持不同的存储引擎,存储引擎管理如何存储和恢复数据。mysql支持多个存储引擎,每个存储引擎具有独特的功能和用途,可以使数据库设计通过使用最合适他们的应用程序的存储引擎来改善数据库系统的性能。例如,如果有一个这样的环境:使用事务控制高度活跃的数据库,请选择一个合适这个情况的存储引擎(mysql的有些存储引擎不支持事务),你还可能会发现这样的视图和表,它们常常被查询但是几乎不被更新(例如查找表),在这种情况下,你可能希望使用存储引擎将这些数据存储在内存中,以便快速访问它们。
InnoDB存储引擎支持事务,在需要事务支持时,通常应该选择这个存储引擎,它是Mysql中目前唯一事务性的引擎。很多第三方存储引擎支持事务,但是仅有InnoDB有"开包即用"选项。有趣的是,InnoDB中所有的索引都是B-trees,在这个B树中索引记录被存储在树的叶子项,InnoDB适用于高性能和事务处理环境。
MyISAM存储引擎是Mysql默认引擎,如果你在create语句中省略了engine选项,那么默认使用这个引擎。MyISAM经常在数据仓库、电子商务和企业应用中使用。MyISAM使用高级缓存和索引机制提高数据检索速度,另外,当各种应用程序需要快速检索数据而不需要事务时,MyISAM将是很好的选择。
Blackhole存储引擎是非常有趣的,它并不存储任何东西。实际上,正如它的名字所言-存储进去的数据永远还会返回。Blackhole存储引擎有个特殊的用途,如果启用了二进制
日志,
SQL命令将被写入这个日志,这时,Blackhole存储引擎被当做复制拓扑中的中继代理使用。
Memory存储引擎(有时被称为HEAP)是内存中的存储器,它使用哈希机制频繁检索被使用过的数据,这样可以更快地检索,它访问数据的方式与其他存储引擎类似,但是数据存储在内存中,并且只在mysql会话有效。当关机时,这些数据被刷新并删除掉。Memory存储引擎通常用于以下情况:静态数据被频繁使用且很少被改变(如查找表).
4)通过Query Cache使用视图来加速结果
5)使用约束
6)使用explain、analyze、optimize
这些工具在诊断和调优时很重要,在不发生错误的前提下经常使用它们,但是请小心使用。具体来说,当analyze、optimize有意义且不是作为定期的预定的事件时使用它们。我们发现有些系统管理员晚上使用这些命令,但是一般情况下,这样做是不值得的,并且会产生不必要的表副本。显然,强制系统定期复制数据浪费时间,并会导致操作过程中的访问有限。