qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

Java Zip文件解压缩

为了解压缩zip都折腾两天了,查看了许多谷歌百度来的code,
  真实无语了,绝大多数是不能用的。这可能跟我的开发环境有关吧。
  我用的是Ubuntu14.04,eclipse 用的是STS3.5,jdk81.8.0_20
  经过两天的努力检验了无数的code终于让我找到一个还能用的可以解决中文乱码问题。
  这个项目用maven构建的依赖jar坐标如下
  <!-- 用于zip文件解压缩 -->
  <dependency>
  <groupId>ant</groupId>
  <artifactId>ant</artifactId>
  <version>1.7.0</version>
  </dependency>
  代码如下:
package com.uujava.mbfy.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.tools.zip.ZipOutputStream;
/**
* @author k
* @date 2014年10月7日 上午8:04:51
* @Description: TODO(用于压缩和解压缩zip文件)
* 尚须解决bug:
* 这里采用硬编码这定文件编码,是否有办法读取压缩文件时判断起内部文件名编码。
*/
public final class ZipUtils {
public static void main(String[] args) throws Exception {
// ZipFile("/home/k/Documents/testzip/宽屏透明html5产品展示.zip", "/home/k/Documents/testzip/index.html");
unZipFile("/home/k/Documents/testzip/宽屏透明html5产品展示.zip",
"/home/k/Documents/testzip/zip");
}
public static void zip(ZipOutputStream out, File f, String base,
boolean first) throws Exception {
if (first) {
if (f.isDirectory()) {
out.putNextEntry(new org.apache.tools.zip.ZipEntry("/"));
base = base + f.getName();
first = false;
} else
base = f.getName();
}
if (f.isDirectory()) {
File[] fl = f.listFiles();
base = base + "/";
for (int i = 0; i < fl.length; i++) {
zip(out, fl[i], base + fl[i].getName(), first);
}
} else {
out.putNextEntry(new org.apache.tools.zip.ZipEntry(base));
FileInputStream in = new FileInputStream(f);
int b;
System.out.println(base);
while ((b = in.read()) != -1) {
out.write(b);
}
in.close();
}
}
@SuppressWarnings("unchecked")
public static void unZipFileByOpache(org.apache.tools.zip.ZipFile zipFile,
String unZipRoot) throws Exception, IOException {
java.util.Enumeration e = zipFile.getEntries();
System.out.println(zipFile.getEncoding());
org.apache.tools.zip.ZipEntry zipEntry;
while (e.hasMoreElements()) {
zipEntry = (org.apache.tools.zip.ZipEntry) e.nextElement();
InputStream fis = zipFile.getInputStream(zipEntry);
if (zipEntry.isDirectory()) {
} else {
File file = new File(unZipRoot + File.separator
+ zipEntry.getName());
File parentFile = file.getParentFile();
parentFile.mkdirs();
FileOutputStream fos = new FileOutputStream(file);
byte[] b = new byte[1024];
int len;
while ((len = fis.read(b, 0, b.length)) != -1) {
fos.write(b, 0, len);
}
fos.close();
fis.close();
}
}
}
public static void ZipFile(String zipFileName, String inputFileName)
throws Exception {
org.apache.tools.zip.ZipOutputStream out = new org.apache.tools.zip.ZipOutputStream(
new FileOutputStream(zipFileName));
out.setEncoding("gbk");// 设置的和文件名字格式一样或开发环境编码设置一样的话就能正常显示了
File inputFile = new File(inputFileName);
zip(out, inputFile, "", true);
System.out.println("zip done");
out.close();
}
public static void unZipFile(String unZipFileName, String unZipPath)
throws Exception {
org.apache.tools.zip.ZipFile zipFile = new org.apache.tools.zip.ZipFile(
unZipFileName, "gbk");
unZipFileByOpache(zipFile, unZipPath);
System.out.println("unZip Ok");
}
}

posted @ 2014-10-09 10:28 顺其自然EVO 阅读(179) | 评论 (0)编辑 收藏

关于测试人员的职业发展

 近期由于项目组人手不够,需要招聘一些测试人员。本周及上周陆陆续续面试了十多个应征者,工作年限在2年~9年之间,但无一满意。期间,种种感叹,回想起去年面试六十余人仅有3人满足要求,如有鲠在喉,还是吐槽一下。如有不对请大家也狂喷我。
  我的要求高么?
  我的要求其实是:有还算不错的沟通能力,熟悉常见软件开发流程,有一定的需求分析、用例设计能力,会基本的linux和sql操作能力。有一些代码能力会加分。这是长期与现实妥协的结果。如果人还算机灵,其实我很愿意花时间来培养他们。
  面试结果
  令人惋惜的是,一个合适的人真的很难找。更令人惋惜的是,我看到好多入行很多年的同行,能力并没有跟随工作年限一同增长,有些做了五六年的人有时候给人感觉竟然还不如一个入行一两年的年轻人。最令人遗憾的是,大部分同学竟然没有一个明确的职业发展思路,即使有,也没有经过深入一些的思考,而是人云亦云。
  面试的一些细节:
  因为从事的工作是业务密集型的,有的业务逻辑非常复杂,我们特意准备了一份不错的需求(考虑到应试者没有行业背景,给出了详尽的专业说明和例子),并根据这份需求出了几道用例设计的题。只有不到四分之一的应试者给出了让人相对满意的答案。我们内部评估这份需求的时候,认为只要有过一两年的用例设计经验,应该能答的不错。
  我一般会根据简历问一些问题,看看简历的真实性。也会问一些基础的测试知识,查看应试者的专业素质。
  常见的问题:
  说说你常用的测试方法? 百分之九十的人只能答出等价类和边界值。只有少数人可以讲出其它测试用例设计方法,但深入问,从没有一个人能有令人满意的回答.
  给一个非常简单的小例子,例如登陆操作,让应试者回答如何使用等价类方法设计用例。但让人吃惊的是仍然只有不到五分之一能够给出比较满意的答案。
  陈述一个缺陷的生命周期(你们是怎么管理bug的?)有一多半人能够说出常见流程,但深入问一些问题:如缺陷如何同版本、测试轮次等结合起来,一些特殊情况如何处理等,很多人就懵了,而这些基本上都是工作中常用的。
  你做的最长的一个项目是什么?在这期间你遇到了什么问题让你最头疼?你如何解决它?十个人里大约只有一人能给出还算不错的答案(能够识别出问题,提出它带来 的不利影响是什么,并能够给出一定的解决方案就算是不错的答案了)。
  你感兴趣的测试工作是什么,你想在哪方面有所发展?十个人里有4个会说是自动化测试,3个会说性能测试,2个会说是管理,一个会说是白盒测试。并希望提供相应培训。只有极少数人能够说出具体的思路和技术项。
  如果继续追问:你说的是性能测试吧?你有过这方面的学习么?一半会说看过一些网站上的技术文章,一半会说看过loadrunner的书。如果继续追问,是哪本书?是哪类文章?有哪些具体的知识点能讲一下么?90%答不上来。
  问:你有看过哪一本测试书籍?哪些技术博客?哪些网站?50%的人会说看过QTP的书(QTP的真正使用率已经快赶上诺基亚的使用率了,国内主流自动化的书竟然还是这个!),并且没有真正在工作中使用过,然后就没有别的了。有少一半人最近几年一本技术书籍也没有看过。
  如果有管理经验的应试者,我会问一些测试过程管理相关的问题,如给一个最简单的题:如果测试时间不够如何?十个人中只会有两三个提到排定优先级和测试裁剪,大部分人的回答竟然是加班也一定要搞完。我想说的:
  1.为了你的前途,请多明确一些个人能力思路吧。你五年后,十年后是个什么样子?有没有一个明确的想法?有没有你五年后想达到的某个人的程度?如果这些思路不清楚,请多看看外面的世界,看看一些测试做得非常好的人是如何工作的,他们掌握了什么能力?学习他们,追赶他们并尝试超越他们。最好认识他们,可以侃侃大山,志同道合抱团前进很好。另外目标别定太抽象,一定要是可以分解,可以检查的。
  2.多读一些测试书籍,测试的书并不是只有QTP!看看微软测试专家史亮推荐的书单,这些都是不错的好书:http://www.cnblogs.com/liangshi/archive/2011/03/07/1973525.html  有些书能够帮助你把测试知识框架搭建起来,比照一下你还缺点啥?
  3.多读一些其它书籍,不限于技术书籍。如果想读的书有利于工作,推荐一些如何做思辨思维的书。《思考的艺术》《六顶思考帽》《你的灯亮着么》 《学会提问》是我喜欢的4本书。它们会教你怎么独立思考,养成提问的习惯,而提问的习惯是我们现在的测试人员最缺乏的一件事情。人们往往拿了被测物就开始忙着写用例,忙着测试。而不是先探索它、研究它。当然IT技术也要掌握,如果你的IT技能能够赶上开发,你发现你做测试的思路会非常的宽广:)
  4.把书籍中的东西跟你的工作对比,把好的东西引入工作(这点是检验书本质量的好方法,也是促进你思考,促进你能力提高的好方法。
  5.关注大牛们的技术博客。国内写好测试博客的人不是很多(很多人其实很有水平,但是不喜欢写blog),但是国外有很多,有人整理了一个list也推荐给大家:http://ssnlove2008.blog.163.com/blog/static/3788942020093284842381/。
  6.搞定你所在行业的领域知识:如常见IT技术,常见业务知识,这些知识掌握的越深,你的价值越高。测试技术是内功,但是你能直接为企业带来价值的最大之处是你对被测物熟悉程度,也就是你的领域知识!!!
  7.没有方向?从你的工作入手,比如,你遇到的最大的难题是什么?我怎么解决它?我需要掌握什么样的技术解决他?我要推动什么样的组织改变来解决它?别人怎么解决它?有没有更好的方法?使用后我改进了那些?google一下别人有没有同样的问题?尝试作对比,如果觉得他做得好,尝试联系那个人讨论一下。看看对方的进展。尝试把活儿干得特别漂亮。你能解决10个中等问题以后,你的能力会有大幅度提高。
  8.尝试做笔记。最好是在线的,推荐印象笔记和有道云笔记。
  9.坚持。
  10.保证身体健康,岁月会给你带来别人的信任感(当然能力要随着岁数增长)。
  能做到这里面的一半,两年后你就能在专业上有高分通过我的面试:)当然肯定你也不见得会看得上我们的offer了。
  11.对于没想好就跳槽,换行业的同学说:你再想想!你的很大价值是与你企业、行业绑定的。如:做了5年保险业务,你的领域知识至少值5w每年,换领域就没了。你在一家公司证明了你自己,到新公司要重新证明你一遍,有的时候外部环境、机遇等会让证明过程很痛苦,成本很高。
  另外的吐槽:
  野蛮生长没有经过系统训练的同学非常多。这其实有很多因素,分析起来觉得有以下几点:
  1.大学或者职业教育没有非常好的课程体系(有些培训机构还行,但是也需要提高),其实测试技能需要系统训练和长时间磨练才能有根本的增长,我们的职业教育或者再教育体系其实还是有很大空白的。
  2.说句实话,大家的读书氛围不够浓厚。大家不喜欢看书。而读书是再教育成本最低,又非常有效的途径。相比于程序员,测试同学喜欢读技术书籍的比率明显的低,这是一个让人悲伤的事实。真希望这种现象能够改变。
  3.很多人是不喜欢coding才转测试,或者是因为IT产业普遍薪水高才来做测试。不是真正热爱这份工作,不热爱其实做不好,因为兴趣是最好的老师。
  4.很多人认为测试门槛低,young talent 不愿意干,测试吸引人才有点儿困难(我初入行的时候也有这种想法,也是当时被强拉来做测试的,当时想做的是coding和数据DBA相关工作并已经有了一些积累,(我没说我是啥人才啊))。说实话测试的入门门槛的确有一点点低,但是做好测试的门槛确是相当的高,随着系统越来越复杂,测试逐渐会比开发还难做,更有挑战性,我这么说你信么?
  5.专业化社区还没有形成规模,测试人员没有能有效交流的平台。这是跟美国和欧洲的一个挺大的差距。他们的社区做得挺好的,我们也有了一些很好的起步。如一些热衷测试公益的同学,一些不错的会议,一些不错的线下活动,但还需要大大的发扬光大。
  真心希望测试行业的整体水平能够逐渐提高起来。
  最后看一下测试大牛James Whittaker(Google测试之道 和 探索式软件测试 的作者)对职业路程发展的一篇文章吧,你会受益很多

posted @ 2014-10-09 10:27 顺其自然EVO 阅读(202) | 评论 (0)编辑 收藏

一键获取软硬件配置及管理员组

作为公司的IT运维,经常要面对集团各种名头的稽查,对我们工作量造成相当大的提高。公司的IT政策不允许使用非法软件、USB口要关闭、电脑使用者不能有管理员权限等等。于是每一个最底层的工作人员一天到晚围着用户的电脑跑,查找硬件配置,软件信息等,为了提高工作效率,于是就写了以下批处理,减轻自己的工作负担。
  功能说明:
  1.扫描机器硬件配置
  2.获取电脑的网络配置
  3.扫描机器软件安装列表
  4.查看Administrators组和Power Users组内的用户
  5.电脑的USB存储端口开关情况
  6.电脑的共享信息
  7.扫描结果自动上传
  扫描的結果以程序画面显示(重要內容)及转出以电脑名称命名的文本文件(详细內容)。并将此文本文件自动上传到共享文件夹中。
  以下是批处理的代码:
@echo off
color 57
title HardSoft Viewer
mode con cols=67 lines=42
setlocal  ENABLEDELAYEDEXPANSION
echo Prepare For View ...
del /f "%TEMP%\temp.txt" 2>nul
dxdiag /t %TEMP%\temp.txt
del /f "%COMPUTERNAME%.txt" 2>nul
echo Start Hardware Viewer ...
echo System Information: >>%COMPUTERNAME%.txt
:system
rem This must 30s
if EXIST "%TEMP%\temp.txt" (
for /f "tokens=1,2,* delims=:" %%a in ('findstr /c:" Machine name:" /c:" Operating System:" /c:" System Model:" /c:" Processor:" /c:"  Memory:" /c:" Card name:" /c:"Display Memory:" "%TEMP%\temp.txt"') do (
set /a tee+=1
if !tee! == 1 echo       Computer Name = %%b>>%COMPUTERNAME%.txt
if !tee! == 2 echo       OS       Type = %%b>>%COMPUTERNAME%.txt
if !tee! == 3 echo       System  Model = %%b>>%COMPUTERNAME%.txt
if !tee! == 4 echo       CPU     Model = %%b>>%COMPUTERNAME%.txt
if !tee! == 5 echo       RAM      Size = %%b>>%COMPUTERNAME%.txt
if !tee! == 6 echo.>>%COMPUTERNAME%.txt
if !tee! == 6 echo DisplayCard : >>%COMPUTERNAME%.txt
if !tee! == 6 echo       Display  Card = %%b>>%COMPUTERNAME%.txt
if !tee! == 7 echo       DisplayMemory = %%b>>%COMPUTERNAME%.txt
)   ) else (
ping /n 2 127.1>nul
goto system
)
set tee=0
echo.>>%COMPUTERNAME%.txt
echo Mother Board:>>%COMPUTERNAME%.txt
for /f "tokens=1,* delims==" %%a in ('wmic BASEBOARD get Manufacturer^,Product^,Version^,SerialNumber /value') do (
set /a tee+=1
if "!tee!" == "3" echo       Manufacturer     = %%b>>%COMPUTERNAME%.txt
if "!tee!" == "4" echo       MotherBoard Model= %%b>>%COMPUTERNAME%.txt
)
set tee=0
)
echo.>>%COMPUTERNAME%.txt
echo Hard Disk: >>%COMPUTERNAME%.txt
for /f "skip=2 tokens=*" %%a in ('wmic DISKDRIVE get model ^,size /value') do (
echo.      %%a>>%COMPUTERNAME%.txt
)
set tee=0
echo.>>%COMPUTERNAME%.txt
echo Network Card:>>%COMPUTERNAME%.txt
for /f "tokens=2* delims==:" %%a in ('ipconfig/all^|find /i "Description" ^| findstr /v "Microsoft" ^| findstr /v "Tunneling"') do (
set  name=%%a
echo      NetCard Model = %%a>>%COMPUTERNAME%.txt
)
for /f "tokens=2* delims==:" %%a in ('ipconfig/all^|find /i "Physical Address" ^| findstr /v "00-00-00-00"') do (
set  name=%%a
echo      MAC Address = %%a>>%COMPUTERNAME%.txt
)
for /f "tokens=2* delims==:" %%a in ('ipconfig/all^|find /i "描述" ^| findstr /v "Microsoft" ^| findstr /v "Tunneling"') do (
set  name=%%a
echo      NetCard Model = %%a>>%COMPUTERNAME%.txt
)
for /f "tokens=2* delims==:" %%a in ('ipconfig/all^|find /i "物理地址" ^| findstr /v "00-00-00-00"') do (
set  name=%%a
echo      MAC Address = %%a>>%COMPUTERNAME%.txt
)
ver|find /i "windows xp">nul 2>nul&&goto xp||goto win7
:xp
for /f "tokens=2* delims==:" %%a in ('ipconfig/all^|find /i "IP Address"') do (
set  name=%%a
echo      IP Address = %%a>>%COMPUTERNAME%.txt
)
echo Start Software Viewer For XP...
echo.>>%COMPUTERNAME%.txt
echo Software Information:>>%COMPUTERNAME%.txt
for /f "tokens=7 delims=\" %%i in ('reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" ^| findstr /v "KB" 2^>nul') do (
for /f "skip=4 tokens=2*" %%a in ('reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\%%i" /v DisplayName 2^>nul' ) do (
echo %%b>>%COMPUTERNAME%.txt
)
)
for /f "tokens=2 delims=\" %%x in ('reg query HKU') do (
for /f "tokens=8 delims=\" %%a in ('reg query "HKU\%%x\Software\Microsoft\Windows\CurrentVersion\Uninstall" 2^>nul') do (
for /f "skip=4 tokens=2*" %%i in ('reg query "HKU\%%x\Software\Microsoft\Windows\CurrentVersion\Uninstall\%%a"  /v "DisplayName" 2^>nul') do (
echo %%j>>%COMPUTERNAME%.txt
)
)
)
echo.>>%COMPUTERNAME%.txt
if exist %windir%\system32\CCM\CcmExec.exe echo "SMS Client has been installed,please uninstall"
if exist %windir%\system32\CCM\CcmExec.exe echo "SMS Client has been installed,please uninstall">>%COMPUTERNAME%.txt
echo ==================================================================
echo USB Information:
echo.>>%COMPUTERNAME%.txt
echo USB Information:>>%COMPUTERNAME%.txt
for /f "skip=4 tokens=2*" %%a in ('reg query "HKLM\SYSTEM\CurrentControlSet\Services\usbstor" /v "start" 2^>nul' ) do (
if "%%b"=="0x4" echo     USB is Close
if "%%b"=="0x3" echo     USB is Open,Please Tag It.
if "%%b"=="0x4" echo     USB is Close>>%COMPUTERNAME%.txt
if "%%b"=="0x3" echo     USB is Open,Please Tag It.>>%COMPUTERNAME%.txt
)
goto last
:win7
for /f "tokens=2* delims==:" %%a in ('ipconfig/all^|find /i "IPV4"') do (
set  name=%%a
echo      IP Address = %%a>>%COMPUTERNAME%.txt
)
echo Start Software Viewer For Win7/8 ...
rem for 32 win7
echo.>>%COMPUTERNAME%.txt
echo Software Information:>>%COMPUTERNAME%.txt
for /f "tokens=7 delims=\" %%i in ('reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" ^| findstr /v "KB" 2^>nul ') do (
for /f "skip=2 tokens=3* delims= " %%a in ('reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\%%i" /v DisplayName 2^>nul') do (
echo %%a %%b>>%COMPUTERNAME%.txt
)
)
for /f "tokens=8 delims=\" %%i in ('reg query "HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" 2^>nul ^| findstr /v "KB" 2^>nul ') do (
for /f "skip=2 tokens=3* delims= " %%a in ('reg query "HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\%%i" /v DisplayName 2^>nul') do (
echo %%a %%b>>%COMPUTERNAME%.txt
)
)
for /f "tokens=2 delims=\" %%x in ('reg query HKU') do (
for /f "tokens=8 delims=\" %%a in ('reg query "HKU\%%x\Software\Microsoft\Windows\CurrentVersion\Uninstall" 2^>nul') do (
for /f "skip=2 tokens=2*" %%i in ('reg query "HKU\%%x\Software\Microsoft\Windows\CurrentVersion\Uninstall\%%a"  /v "DisplayName" 2^>nul') do (
echo %%j>>%COMPUTERNAME%.txt
)
)
)
for /f "tokens=2 delims=\" %%x in ('reg query HKU') do (
for /f "tokens=9 delims=\" %%a in ('reg query "HKU\%%x\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" 2^>nul') do (
for /f "skip=2 tokens=2*" %%i in ('reg query "HKU\%%x\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\%%a"  /v "DisplayName" 2^>nul') do (
echo %%j>>%COMPUTERNAME%.txt
)
)
)
echo ==================================================================
echo USB Information:
echo.>>%COMPUTERNAME%.txt
echo USB Information:>>%COMPUTERNAME%.txt
for /f "skip=2 tokens=2*" %%a in ('reg query "HKLM\SYSTEM\CurrentControlSet\Services\usbstor" /v "start" 2^>nul' ) do (
if "%%b"=="0x4" echo     USB is Close
if "%%b"=="0x3" echo     USB is Open,Please Tag It.
if "%%b"=="0x4" echo     USB is Close>>%COMPUTERNAME%.txt
if "%%b"=="0x3" echo     USB is Open,Please Tag It.>>%COMPUTERNAME%.txt
)
:last
echo ==================================================================
echo Admin Users:
echo.>>%COMPUTERNAME%.txt
echo Admin Users:>>%COMPUTERNAME%.txt
for /f "skip=6 tokens=*" %%i in ('net localgroup Administrators ^| findstr /v "㏑" ^| findstr /v "命" ^| findstr /v "command"') do (
echo       %%i
echo       %%i>>%COMPUTERNAME%.txt
)
echo Power Users:
echo.>>%COMPUTERNAME%.txt
echo Power Users:>>%COMPUTERNAME%.txt
for /f "skip=6 tokens=*" %%i in ('net localgroup "Power Users" ^| findstr /v "㏑" ^| findstr /v "命" ^| findstr /v "command"') do (
echo       %%i
echo       %%i>>%COMPUTERNAME%.txt
)
echo ==================================================================
echo FileShare Information:
echo.>>%COMPUTERNAME%.txt
echo FileShare Information:>>%COMPUTERNAME%.txt
for /f "skip=4 tokens=*" %%i in ('net share 2^>nul ^| findstr /v "㏑" ^| findstr /v "命" ^| findstr /v "command"' ) do (
echo  %%i
echo  %%i>>%COMPUTERNAME%.txt
)
echo =========================Viewer Over==============================
net use \\192.168.1.1 password /user:username 1>nul 2>nul
copy %COMPUTERNAME%.txt \\192.168.1.1\HardFile$\
net use \\192.168.1.1\IPC$ /del 1>nul 2>nul
pause
start %COMPUTERNAME%.txt
 現在來查看下掃描結果XP/WIN8對比
  以及產生的掃描結果
System Information:
Computer Name =  C0300022B068
OS       Type =  Windows 8.1 专业版 64-bit (6.3, Build 9600) (9600.winblue_gdr.131030-1505)
System  Model =  System Product Name
CPU     Model =  Pentium(R) Dual-Core  CPU      E5500  @ 2.80GHz (2 CPUs), ~2.8GHz
RAM      Size =  4096MB RAM
DisplayCard =
Display  Card =  Microsoft 基本显示适配器
DisplayMemory =  256 MB
Mother Board:
Manufacturer     = ASUSTeK Computer INC.
MotherBoard Model= P5KPL-AM
Hard Disk:
Model=ST3500418AS ATA Device
Size=500038694400
Network Card:
NetCard Model =  Realtek PCIe FE Family Controller
MAC Address =  00-23-54-0A-31-A9
IP Address =  172.17.44.103(首选)
Software Information:
谷歌拼音输入法 2.7
7-Zip 9.30 (x64 edition)
Windows Live MIME IFilter
Java 8 Update 20 (64-bit)
Microsoft Visual C++ 2008 Redistributable - x64 9.0.30729.4148
Java SE Development Kit 8 Update 20 (64-bit)
Microsoft Application Error Reporting
PDF-Viewer
Microsoft Visual C++ 2005 Redistributable (x64)
MSVCRT110_amd64
VIA 平台设备管理员
Mozilla Maintenance Service
Notepad++
Windows Live 软件包
Windows Live UX Platform
Windows Live Writer
Windows Live UX Platform Language Pack
Junk Mail filter update
Radmin Viewer 3.5
Windows Live Photo Common
Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.4148
Platform
Windows Live 软件包
Windows Live Writer
Windows Live Writer
微软设备健康助手
Windows Live Communications Platform
Java Auto Updater
Windows Live Mail
Windows Live Writer Resources
LibreOffice 4.3.0.4
Windows Live Installer
Windows Live Writer
Windows Live Writer Resources
Windows Live UX Platform Language Pack
Windows Live 程式集
Microsoft Visual C++ 2005 Redistributable
Photo Common
MSVCRT
MSVCRT110
Microsoft Visual C++ 2008 Redistributable - x86 9.0.21022
Adobe Reader 8 - Chinese Traditional
Windows Live PIMT Platform
Windows Live Mail
Windows Live Mail
Windows Live SOXE
MSVCRT_amd64
Windows Live SOXE Definitions
Photo Common
D3DX10
Microsoft WSE 3.0 Runtime
Microsoft Visual C++ 2008 Redistributable - x86 9.0.21022.218
Microsoft WSE 2.0 SP3 Runtime
USB Information:
USB is Open,Please Tag It.
Admin Users:
Administrator
Luke
Power Users:
FileShare Information:
ADMIN$       C:\Windows                      远程管理
C$           C:\                             默认共享
IPC$                                         远程 IPC
D$           D:\                             默认共享
E$           E:\                             默认共享
F$           F:\                             默认共享
HardFile$    D:\HardFile
cd_rom       D:\cd_rom
HardSoftViewer
D:\HardSoftViewer
HardwareViewer 20140923
D:\HardwareViewer 20140923
public       D:\public

posted @ 2014-10-09 10:24 顺其自然EVO 阅读(349) | 评论 (0)编辑 收藏

一次关于缺陷状态的争论

在我们的缺陷库中,有一种缺陷状态为“待提交”,这是一种最终状态,并且表明这个缺陷实际上是无效的,不会计入到最终的缺陷报告中。
  一个项目开始了,在几个版本之后,缺陷库中存在数个“待提交”状态的缺陷,原因无外乎几种:与其它缺陷重复、测试人员的失误等。
  再来说由此产生的争论:一个同事认为,“待提交”状态的缺陷不应当存在于缺陷库中。从字面上来理解,“待提交”就是提交之前的预状态,将其修改为有效的缺陷后重新置为“新建”状态。这样从缺陷库来看,不会暴露出测试人员的失误,可以给上级或其他人一种测试非常高效的印象。
  但我不这么认为:无论是重复的缺陷也好,测试人员的失误也好,这都是系统测试过程中一种真实的反应和记录,并且这是不可避免一定会出现的。在测试活动结束之后,可以对所有“待提交”状态的缺陷做统一的分析,指导后续的测试活动。也就是说“待提交”状态的缺陷也是一种资源,可以挖掘出有用的信息来。如果人为的使其消失,尽管表面上看来显示出测试的高效,但是真正了解软件测试过程的人必然也能发现其中的可疑之处。
  关于争论的结果,我只能说对方才是这个项目的负责人。

posted @ 2014-10-09 10:22 顺其自然EVO 阅读(196) | 评论 (0)编辑 收藏

CentOS安装搭建BugFree

BugFree基于PHP和MySQL开发,是免费且开发源代码的缺陷管理系统。服务器端在LinuxWindows平台上都可以运行;客户端无需安装任何软件,通过IE,FireFox等浏览器就可以自由使用。
  BugFree 2 在BugFree 1.1的基础上,集成了Test Case和Test Result的管理功能。具体使用流程是:首先创建Test Case(测试用例),运行Test Case产生Test Result(测试结果),运行结果为Failed的Case,可以直接创建Bug。Test Case标题、步骤和Test Result运行环境等信息直接复制到新建的Bug中。
  关闭selinux:
  # vim /etc/selinux/config
  将配置文件中 SELINUX=permissive
  关闭iptables
  # chkconfig --level 35 iptables off
  [root@bugfree ~]# chkconfig --list |grep iptables   查看iptables状态     0:off 1:off 2:on 3:off 4:on 5:off 6:off
  1. 安装apache
  yum install httpd
  2. 安装mysql
  yum install mysql mysql-server
  注:已安装mysql的跳过此步骤
  3. 安装PHP
  yum install php php-mysql php-gd php-imap php-ldap php-odbc php-pear php-xml php-xmlrpc
  4. 安装PHP加密算法插件
  yum install libmcrypt
  yum install php-mcrypt
  centos 6.x 默认yum源没有libmcrypt 相关的包
  从这里下载: http://www.lishiming.net/data/attachment/forum/month_1211/epel-release-6-7.noarch.rpm
  然后再
  yum install -y  libmcrypt-devel   即可解决安装php加密算法找不到yum源的问题
  注:libmcrypt是加密算法扩展库,php-mcrypt是Mcrypt对PHP的一个扩展
  5. 安装bugfree
  bugfree官网已停止对它进行更新,我在百度搜索的一个版本是:bugfree3.0.4
  解压:unzip bugfree3.zip
  重命名解压后的文件:mv bugfree3 bugfree
  把bugfree放到apache的DocumentRoot:mv bugfree /var/www/html
  改变bugfree的读写权限:chmod -R 777 bugfree
  6. 配置
  1) 配置apache
  vi /etc/httpd/conf/httpd.conf
  修改默认端口号 Listen 80 --> Listen 7999
  启动httpd服务:service httpd start
 2) 配置mysql
  启动mysqld服务:service mysqld start
  注:mysqld服务已启动的跳过此步骤
  登陆mysql:mysql -uroot -p
  创建新用户:CREATE USER 'bugfree'@'localhost' IDENTIFIED BY '123456';
  新用户授权:grant all privileges on *.* to bugfree@localhost identified by '123456';
  注:以上授权方式需要把mysql和bugfree安装在同一台机器上
  3) 配置bugfree
  浏览器访问http://<servername>:port/bugfree/install
  例如:http://192.168.1.20:7999/bugfree/install
  安装第一步有个提示/var/www/html/BugFile/  文件不可读不可写
  创建BugFile文件夹  mkdir BugFile
  chmod -R 777 BugFile 即可解决
  按照提示配置bugfree关联的数据库
  注:要在root权限下操作,即用root登陆或者sudo来操作
  7. 完成安装,进入BugFree
  初始用户名: admin 初始密码:123456
  查看是否已经是开机启动:chkconfig --list|grep httpd
  [root@localhost ~]# chkconfig --list|grep httpd
  mysql           0:关闭  1:关闭  2:关闭  3:关闭  4:关闭  5:关闭  6:关闭
  0:关机。
  1:单用户字符界面。
  2:不具备网络文件系统(NFS)功能的多用户字符界面。
  3:具有网络功能的多用户字符界面。
  4: 保留不用。
  5:具有网络功能的图形用户界面。
  6:重新启动系统。
  用命令 chkconfig --level 2345 mysqld on (更改相应级别即可)更改httpd随系统启动状态

posted @ 2014-10-09 10:21 顺其自然EVO 阅读(846) | 评论 (0)编辑 收藏

VS2010的反汇编功能测试

 F10单步执行前
  F10单步执行后

posted @ 2014-10-09 10:20 顺其自然EVO 阅读(181) | 评论 (0)编辑 收藏

如何写更好的自动化测试用例

抱歉, 文章的开头我需要先给这个[自动化测试用例]设一个范围. 自动化用例的形式有很多, 根据测试对象和测试环境的不同, 有各种script和自动化框架来支持你开发出各式各样的用例.
  而本文是基于Robot Framework, 一种keyword driven(关键字驱动)的自动化测试框架来讲的. 如果你是被题目给骗进来的, 那就说明我的第一个目的已经达到了, 哈哈!
  关于更多Robot Framework的信息请google.
  工作中我经常需要去review其他同事的自动化用例(是的,像软件代码那样被review). 我通常从4个方面来审查用例的质量:Readability, Maintainability, Reliability, Performance,
  而这4个方面可以具体到下面这些具体工作:
  Coding Style
  良好的规范可以极大的增强用例的可读性和可维护性. 当这些用例被转交给他人时, 也会因为相同的coding style增加对方的接受度.
  当一位"新人"参与用例编写时我会首先把注意力放到Coding Style上, 因为这也是最容易做到的. 为此我们定义了一些规范:
  a.好的命名规范
  文件名不能包含特殊符号并且遵照特定的格式. 不同作用域的变量采用不同的命名方式, 变量名描述的更有意义, 全局变量要在Variables表中定义..
  还有case的命名、keyword、case setup、teardown.
  b.documentation
  作为用例的补充信息documentation是必不可少的,如果测试用例本身或者背景太过复杂, 我们还可以给suite、test case、keyword分级加注释.
  c.tags
  给用例打上正确的标签.标签的应用非常的广泛和灵活既可以拿来做用例筛选、版本管理、统计、调度策略,还可以为一些测试策略如[基于风险的测试]提供方案.
  d....
  让case读起来像文档
  在考虑Coding Style时我们可以设置一些固定的规则,大家只要按照这个规则来做,实践几次之后Coding Style就会趋于统一. 而考虑将case写的如同文档一般则需要更多的主观能动性.
  为什么需要这样的mindset? 公司开始推行敏捷之后,测试也在不断的追求更敏捷的测试.敏捷强调 "快速进入, 不断迭代", 而文档在整个开发过程中不可避免的被弱化, 需求设计不断的更新,
  文档往往不能被很及时的更新. 那么怎样可以让测试人员如何快速的掌握某个功能或者产品的需求和当前状态呢? 答案是用例.
  a.简洁明了的documatation
  通过增加[用例注释]来增强用例的可读性是一个不错的办法.一个suite文件往往包含了一组测试用例,suite level的documation通常可以包含该组测试的背景信息、这组测试的目的、特殊的环境配置说明等.
  要控制documatation的长度,可以通过添加link来扩展更多信息.不要过多的描述测试的详细内容,用例本身应该对其有很好的描述.也不要因为文档而文档,将case名或者重复的信息放在上面.
  case level的documatation我们觉得一般情况下是不需要的, 因为case的结构本身应该足够清楚的描述.
  b.清晰的用例名
  用例文件名应该能简单描述文件内所有case的测试目的.我们建立一个目录来存储测试点相近的测试用例, 目录名可以更抽象, 然后我们给这个用例一致的命名规则.
  这样当在你浏览一组用例时,仅仅通过用例名就能大致了解里面的测试内容,也方便你寻找某个case. 应该更多的从用户角度来思考文件名,对比下面两个文件名:
  Suite Name1: creation handling after remove unnecessary fatal error.html
  Suite Name2: Avoid DSP restart by removing unnecessary fatal error when timeout happened during call creation.html
  c.条例清晰的case step
  case name
  case step
  keyword
  case的独立性
  通常一个test suite包含了一组相近的或者有关联的test case. 而每一个test case应该只测试一种场景,根据case复杂程度的不同场景同样可大可小,可以是某个功能的测试也可以是端到端的完整测试.(当然也有特殊的写法比如工作流测试和数据驱动.) case的独立性又有哪些需要关注的点呢?
  首先一个test suite内的test case在执行时不应该相互影响, 应该将通用的背景部分提取出来放到suite setup中, 允许我随机的跑某一个case或者乱序的跑这些case. 如果case的步骤有造成环境被破坏的风险,那应该在case teardown中将环境恢复,并且在case setup中做环境监察以及时的终止case. suite level和folder level同样要注意独立性的问题,在CRT中通常会将数百数千的case放在一起跑,robot并不会规定case执行的顺序所以从某种程度上来说它是随机的.独立性还体现在case fail时信息的抓取上,经过一个晚上大批case的执行之后,环境通常已被破坏, 希望通过保留现场来用作case失败问题定位是不现实的.
  所以每个case都应该准确的收集其开始和结束之间的信息.
  case的可迁移性
  case的可迁移性主要考虑:case对执行环境的依赖,case对外部设备的依赖,case对测试对象的依赖.
  a.避免依赖执行环境,你一直在个人PC上编写的用例并执行测试,但是不久之后你的用例就会被迁移到组内的测试执行服务器上,之后又被部署到持续集成服务器上,
  中途也有可能被其他同事下载到他的个人PC上来执行测试.所以在编写用例时我们要避免支持不同平台的不同库(windows,linux)和或者不同的脚本命令(CentOS,RedHat,MacOS)
  总之要像Java宣扬的那样"一处编译处处运行".
  b.在通信领域为了测试需要或者扩展测试覆盖,我们会引入一些外部设备如Spirent、Cisco的一些辅助测试设备,各种网络设备交换机、路由器,还有一些自行开发的模拟设备.
  外部设备会不断的升级或者更换,在编写用例时我们就需要考虑如何用一套case更好的兼容这些测试设备. 我有如下几点建议:
 i.首先将外部设备的操作从测试用例步骤中剥离出去,组织成组级别的库.
  ii.
  c.对测试对象的依赖,这里我考虑到的是如果测试对象是一个软件平台,软件平台通常需要适配多种的设备.而设备的硬件配置可能是多种多样的,CPU、内存、组件的性能和数量都可能不同.
  对测试对象的依赖不仅要考虑在不同设备上的可执行性,重点要考虑测试覆盖率,由于设备组件的增多你的用例可能无法覆盖到这些组件,或者捕捉不到某个性能瓶颈,这样测试结果的可靠性也大打折扣.
  case的可重用性
  自动化用例的开发通常是一项费时的工作,它需要的时间会是手动执行用例的10倍、20倍甚至更多. 我们通过搭建测试框架和封装资源库来实现最大范围的可重用性.
  这里我考虑用例的可重用性包括两块:逻辑层的抽象和业务层的重用.
  对一个产品或者功能进行自动化工作时,我们要考虑这些可用性:首先根据测试逻辑的不同对测试用例进行分类,根据逻辑的不同选择搭建有针对性的case框架,Work Flow, Data Driven等.
  建立公共的库,将业务的原子操作抽象出来,并且鼓励其他同事对库进行补充和调用,避免duplicated库开发.抽象的API通常需要足够的原子和灵活才会被大众所接受. 基于底层API编写的业务操作也具备可重用性,比方说测试场景(背景资源)的建立、工作流的操作组合、检查点都可以被复用. 层次分明的抽取时重用性的基础,提高可重用性可以减少开发时间,也方便日后的维护中的迭代修改.
  case的效率
  不同的case执行时间相距甚远,短则数秒长则数小时甚至数天,数秒钟的简单功能测试用例和稳定性测试耗时数天的用例本身是没有什么可比性的.但是我当我们放眼某一个或者某一组case时,我们需要重视效率.不论是敏捷还是持续集成都讲究快速的反馈,开发人员能在提交代码后快速的获得测试结果反馈,测试人员能在最短的时间内执行更大范围的测试覆盖,不仅能提高团队的工作效率也可增强团队的信心.
  在编写用例时我们应该注意哪些方面来提高用例的性能?
  对于单一的case我的注意点多放在一些细节上,例如:
  1.执行条件的检查,如果检查失败,则尽快退出执行.
  2.将执行环境搭建或者资源建立和清除 抽取到suite甚至folder level, 抽取时可能需要做一些组合, 但决不允许出现重复的建删操作.
  3.用例中不允许出现sleep,sleep通常紧接着hard code的时间,不仅效率低还会因为环境的切换使得执行失败.建议用"wait until ..."来代替.
  4.如有不可避免的sleep,我通常会再三确认其是否清楚它的必要性.
  对于批量的case,我们要如何才能获得更高的效率呢?
  1.首先我们考虑到可以并行的执行一组case来提高效率,并行方案总有着严苛的条件:
  2.为了获得更快的反馈,我们将软件质量分为0~10级,对应的把测试用例分为6~10级,从普通的功能测试开始测试复杂度逐级递增.
  不同的开发阶段或者是针对不同的测试目的我们就可以有选择的调用不同级别的用例.比方说我们调用6级的cases来测试新功能代码作为冒烟测试的用例集;软件人员修改了BUG,我可以根据BUG的复杂度选择7和8级的用例来验证,系统级测试时我们又会主要测试8和9级的用例.
  分级可以灵活调度用例,并给出更快的反馈,加速迭代过程.
  3.基于风险的测试
  基于风险的测试简单的说就是根据优先级来选择需要运行的测试,优先级根据两个最基本的维度:
  功能点发生错误的概率,以及发生错误后的严重性,根据两者分值的乘积来排序优先级.
  一般从用例失败率,bug统计,出错的代码段,更新的代码段来考虑调度.比方说根据BUG修改的代码段和功能区域来选择对应的测试.开发人员通常反对这种方式,只有100%的测试覆盖才能给他们足够的信心.
  以上是个人的一些积累,由于框架的限制一些建议不一定适用于你的实际工作. 如果你有什么建议欢迎留言. Thx!

posted @ 2014-10-09 10:16 顺其自然EVO 阅读(748) | 评论 (0)编辑 收藏

编写属于你的第一个Linux内核模块

 内核编程常常看起来像是黑魔法,而在亚瑟 C 克拉克的眼中,它八成就是了。Linux内核和它的用户空间是大不相同的:抛开漫不经心,你必须小心翼翼,因为你编程中的一个bug就会影响到整个系统。浮点运算做起来可不容易,堆栈固定而狭小,而你写的代码总是异步的,因此你需要想想并发会导致什么。而除了所有这一切之外,Linux内核只是一个很大的、很复杂的C程序,它对每个人开放,任何人都去读它、学习它并改进它,而你也可以是其中之一。
  学习内核编程的最简单的方式也许就是写个内核模块:一段可以动态加载进内核的代码。模块所能做的事是有限的——例如,他们不能在类似进程描述符这样的公共数据结构中增减字段(LCTT译注:可能会破坏整个内核及系统的功能)。但是,在其它方面,他们是成熟的内核级的代码,可以在需要时随时编译进内核(这样就可以摒弃所有的限制了)。完全可以在Linux源代码树以外来开发并编译一个模块(这并不奇怪,它称为树外开发),如果你只是想稍微玩玩,而并不想提交修改以包含到主线内核中去,这样的方式是很方便的。
  在本教程中,我们将开发一个简单的内核模块用以创建一个/dev/reverse设备。写入该设备的字符串将以相反字序的方式读回(“Hello World”读成“World Hello”)。这是一个很受欢迎的程序员面试难题,当你利用自己的能力在内核级别实现这个功能时,可以使你得到一些加分。在开始前,有一句忠告:你的模块中的一个bug就会导致系统崩溃(虽然可能性不大,但还是有可能的)和数据丢失。在开始前,请确保你已经将重要数据备份,或者,采用一种更好的方式,在虚拟机中进行试验。
  尽可能不要用root身份
  默认情况下,/dev/reverse只有root可以使用,因此你只能使用sudo来运行你的测试程序。要解决该限制,可以创建一个包含以下内容的/lib/udev/rules.d/99-reverse.rules文件:
  SUBSYSTEM=="misc", KERNEL=="reverse", MODE="0666"
  别忘了重新插入模块。让非root用户访问设备节点往往不是一个好主意,但是在开发其间却是十分有用的。这并不是说以root身份运行二进制测试文件也不是个好主意。
  模块的构造
  由于大多数的Linux内核模块是用C写的(除了底层的特定于体系结构的部分),所以推荐你将你的模块以单一文件形式保存(例如,reverse.c)。我们已经把完整的源代码放在GitHub上——这里我们将看其中的一些片段。开始时,我们先要包含一些常见的文件头,并用预定义的宏来描述模块:
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Valentine Sinitsyn <valentine.sinitsyn@gmail.com>");
  MODULE_DESCRIPTION("In-kernel phrase reverser");
  这里一切都直接明了,除了MODULE_LICENSE():它不仅仅是一个标记。内核坚定地支持GPL兼容代码,因此如果你把许可证设置为其它非GPL兼容的(如,“Proprietary”[专利]),某些特定的内核功能将在你的模块中不可用。
  什么时候不该写内核模块
  内核编程很有趣,但是在现实项目中写(尤其是调试)内核代码要求特定的技巧。通常来讲,在没有其它方式可以解决你的问题时,你才应该在内核级别解决它。以下情形中,可能你在用户空间中解决它更好:
  你要开发一个USB驱动 —— 请查看libusb。
  你要开发一个文件系统 —— 试试FUSE。
  你在扩展Netfilter —— 那么libnetfilter_queue对你有所帮助。
  通常,内核里面代码的性能会更好,但是对于许多项目而言,这点性能丢失并不严重。
  由于内核编程总是异步的,没有一个main()函数来让Linux顺序执行你的模块。取而代之的是,你要为各种事件提供回调函数,像这个:
  static int __init reverse_init(void)
  {
  printk(KERN_INFO "reverse device has been registered\n");
  return 0;
  }
  static void __exit reverse_exit(void)
  {
  printk(KERN_INFO "reverse device has been unregistered\n");
  }
  module_init(reverse_init);
  module_exit(reverse_exit);
 这里,我们定义的函数被称为模块的插入和删除。只有第一个的插入函数是必要的。目前,它们只是打印消息到内核环缓冲区(可以在用户空间通过dmesg命令访问);KERN_INFO是日志级别(注意,没有逗号)。__init和__exit是属性 —— 联结到函数(或者变量)的元数据片。属性在用户空间的C代码中是很罕见的,但是内核中却很普遍。所有标记为__init的,会在初始化后释放内存以供重用(还记得那条过去内核的那条“Freeing unused kernel memory…[释放未使用的内核内存……]”信息吗?)。__exit表明,当代码被静态构建进内核时,该函数可以安全地优化了,不需要清理收尾。最后,module_init()和module_exit()这两个宏将reverse_init()和reverse_exit()函数设置成为我们模块的生命周期回调函数。实际的函数名称并不重要,你可以称它们为init()和exit(),或者start()和stop(),你想叫什么就叫什么吧。他们都是静态声明,你在外部模块是看不到的。事实上,内核中的任何函数都是不可见的,除非明确地被导出。然而,在内核程序员中,给你的函数加上模块名前缀是约定俗成的。
  这些都是些基本概念 – 让我们来做更多有趣的事情吧。模块可以接收参数,就像这样:
  # modprobe foo bar=1
  modinfo命令显示了模块接受的所有参数,而这些也可以在/sys/module//parameters下作为文件使用。我们的模块需要一个缓冲区来存储参数 —— 让我们把这大小设置为用户可配置。在MODULE_DESCRIPTION()下添加如下三行:
  static unsigned long buffer_size = 8192;
  module_param(buffer_size, ulong, (S_IRUSR | S_IRGRP | S_IROTH));
  MODULE_PARM_DESC(buffer_size, "Internal buffer size");
  这儿,我们定义了一个变量来存储该值,封装成一个参数,并通过sysfs来让所有人可读。这个参数的描述(最后一行)出现在modinfo的输出中。
  由于用户可以直接设置buffer_size,我们需要在reverse_init()来清除无效取值。你总该检查来自内核之外的数据 —— 如果你不这么做,你就是将自己置身于内核异常或安全漏洞之中。
  static int __init reverse_init()
  {
  if (!buffer_size)
  return -1;
  printk(KERN_INFO
  "reverse device has been registered, buffer size is %lu bytes\n",
  buffer_size);
  return 0;
  }
  来自模块初始化函数的非0返回值意味着模块执行失败。
  导航
  但你开发模块时,Linux内核就是你所需一切的源头。然而,它相当大,你可能在查找你所要的内容时会有困难。幸运的是,在庞大的代码库面前,有许多工具使这个过程变得简单。首先,是Cscope —— 在终端中运行的一个比较经典的工具。你所要做的,就是在内核源代码的顶级目录中运行make cscope && cscope。Cscope和Vim以及Emacs整合得很好,因此你可以在你最喜爱的编辑器中使用它。
  如果基于终端的工具不是你的最爱,那么就访问http://lxr.free-electrons.com吧。它是一个基于web的内核导航工具,即使它的功能没有Cscope来得多(例如,你不能方便地找到函数的用法),但它仍然提供了足够多的快速查询功能。
  现在是时候来编译模块了。你需要你正在运行的内核版本头文件(linux-headers,或者等同的软件包)和build-essential(或者类似的包)。接下来,该创建一个标准的Makefile模板:
  obj-m += reverse.o
  all:
  make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
  clean:
  make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
  现在,调用make来构建你的第一个模块。如果你输入的都正确,在当前目录内会找到reverse.ko文件。使用sudo insmod reverse.ko插入内核模块,然后运行如下命令:
  $ dmesg | tail -1
  [ 5905.042081] reverse device has been registered, buffer size is 8192 bytes
  恭喜了!然而,目前这一行还只是假象而已 —— 还没有设备节点呢。让我们来搞定它。
  混杂设备
  在Linux中,有一种特殊的字符设备类型,叫做“混杂设备”(或者简称为“misc”)。它是专为单一接入点的小型设备驱动而设计的,而这正是我们所需要的。所有混杂设备共享同一个主设备号(10),因此一个驱动(drivers/char/misc.c)就可以查看它们所有设备了,而这些设备用次设备号来区分。从其他意义来说,它们只是普通字符设备。
  要为该设备注册一个次设备号(以及一个接入点),你需要声明struct misc_device,填上所有字段(注意语法),然后使用指向该结构的指针作为参数来调用misc_register()。为此,你也需要包含linux/miscdevice.h头文件:
  static struct miscdevice reverse_misc_device = {
  .minor = MISC_DYNAMIC_MINOR,
  .name = "reverse",
  .fops = &reverse_fops
  };
  static int __init reverse_init()
  {
  ...
  misc_register(&reverse_misc_device);
  printk(KERN_INFO ...
  }
  这儿,我们为名为“reverse”的设备请求一个第一个可用的(动态的)次设备号;省略号表明我们之前已经见过的省略的代码。别忘了在模块卸下后注销掉该设备。
  static void __exit reverse_exit(void)
  {
  misc_deregister(&reverse_misc_device);
  ...
  }
  ‘fops’字段存储了一个指针,指向一个file_operations结构(在Linux/fs.h中声明),而这正是我们模块的接入点。reverse_fops定义如下:
  static struct file_operations reverse_fops = {
  .owner = THIS_MODULE,
  .open = reverse_open,
  ...
  .llseek = noop_llseek
  };
  另外,reverse_fops包含了一系列回调函数(也称之为方法),当用户空间代码打开一个设备,读写或者关闭文件描述符时,就会执行。如果你要忽略这些回调,可以指定一个明确的回调函数来替代。这就是为什么我们将llseek设置为noop_llseek(),(顾名思义)它什么都不干。这个默认实现改变了一个文件指针,而且我们现在并不需要我们的设备可以寻址(这是今天留给你们的家庭作业)。
  关闭和打开
  让我们来实现该方法。我们将给每个打开的文件描述符分配一个新的缓冲区,并在它关闭时释放。这实际上并不安全:如果一个用户空间应用程序泄漏了描述符(也许是故意的),它就会霸占RAM,并导致系统不可用。在现实世界中,你总得考虑到这些可能性。但在本教程中,这种方法不要紧。
  我们需要一个结构函数来描述缓冲区。内核提供了许多常规的数据结构:链接列表(双联的),哈希表,树等等之类。不过,缓冲区常常从头设计。我们将调用我们的“struct buffer”:
  struct buffer {
  char *data, *end, *read_ptr;
  unsigned long size;
  };
  data是该缓冲区存储的一个指向字符串的指针,而end指向字符串结尾后的第一个字节。read_ptr是read()开始读取数据的地方。缓冲区的size是为了保证完整性而存储的 —— 目前,我们还没有使用该区域。你不能假设使用你结构体的用户会正确地初始化所有这些东西,所以最好在函数中封装缓冲区的分配和收回。它们通常命名为buffer_alloc()和buffer_free()。
  static struct buffer buffer_alloc(unsigned long size) { struct buffer *buf; buf = kzalloc(sizeof(buf), GFP_KERNEL); if (unlikely(!buf)) goto out; … out: return buf; }
  内核内存使用kmalloc()来分配,并使用kfree()来释放;kzalloc()的风格是将内存设置为全零。不同于标准的malloc(),它的内核对应部分收到的标志指定了第二个参数中请求的内存类型。这里,GFP_KERNEL是说我们需要一个普通的内核内存(不是在DMA或高内存区中)以及如果需要的话函数可以睡眠(重新调度进程)。sizeof(*buf)是一种常见的方式,它用来获取可通过指针访问的结构体的大小。
  你应该随时检查kmalloc()的返回值:访问NULL指针将导致内核异常。同时也需要注意unlikely()宏的使用。它(及其相对宏likely())被广泛用于内核中,用于表明条件几乎总是真的(或假的)。它不会影响到控制流程,但是能帮助现代处理器通过分支预测技术来提升性能。
  最后,注意goto语句。它们常常为认为是邪恶的,但是,Linux内核(以及一些其它系统软件)采用它们来实施集中式的函数退出。这样的结果是减少嵌套深度,使代码更具可读性,而且非常像更高级语言中的try-catch区块。
  有了buffer_alloc()和buffer_free(),open和close方法就变得很简单了。
  static int reverse_open(struct inode *inode, struct file *file)
  {
  int err = 0;
  file->private_data = buffer_alloc(buffer_size);
  ...
  return err;
  }
  struct file是一个标准的内核数据结构,用以存储打开的文件的信息,如当前文件位置(file->f_pos)、标志(file->f_flags),或者打开模式(file->f_mode)等。另外一个字段file->privatedata用于关联文件到一些专有数据,它的类型是void *,而且它在文件拥有者以外,对内核不透明。我们将一个缓冲区存储在那里。
  如果缓冲区分配失败,我们通过返回否定值(-ENOMEM)来为调用的用户空间代码标明。一个C库中调用的open(2)系统调用(如glibc)将会检测这个并适当地设置errno 。
  学习如何读和写
  “read”和“write”方法是真正完成工作的地方。当数据写入到缓冲区时,我们放弃之前的内容和反向地存储该字段,不需要任何临时存储。read方法仅仅是从内核缓冲区复制数据到用户空间。但是如果缓冲区还没有数据,revers_eread()会做什么呢?在用户空间中,read()调用会在有可用数据前阻塞它。在内核中,你就必须等待。幸运的是,有一项机制用于处理这种情况,就是‘wait queues’。
  想法很简单。如果当前进程需要等待某个事件,它的描述符(struct task_struct存储‘current’信息)被放进非可运行(睡眠中)状态,并添加到一个队列中。然后schedule()就被调用来选择另一个进程运行。生成事件的代码通过使用队列将等待进程放回TASK_RUNNING状态来唤醒它们。调度程序将在以后在某个地方选择它们之一。Linux有多种非可运行状态,最值得注意的是TASK_INTERRUPTIBLE(一个可以通过信号中断的睡眠)和TASK_KILLABLE(一个可被杀死的睡眠中的进程)。所有这些都应该正确处理,并等待队列为你做这些事。
  一个用以存储读取等待队列头的天然场所就是结构缓冲区,所以从为它添加wait_queue_headt read\queue字段开始。你也应该包含linux/sched.h头文件。可以使用DECLARE_WAITQUEUE()宏来静态声明一个等待队列。在我们的情况下,需要动态初始化,因此添加下面这行到buffer_alloc():
  init_waitqueue_head(&buf->read_queue);
  我们等待可用数据;或者等待read_ptr != end条件成立。我们也想要让等待操作可以被中断(如,通过Ctrl+C)。因此,“read”方法应该像这样开始:
static ssize_t reverse_read(struct file *file, char __user * out,
size_t size, loff_t * off)
{
struct buffer *buf = file->private_data;
ssize_t result;
while (buf->read_ptr == buf->end) {
if (file->f_flags & O_NONBLOCK) {
result = -EAGAIN;
goto out;
}
if (wait_event_interruptible
(buf->read_queue, buf->read_ptr != buf->end)) {
result = -ERESTARTSYS;
goto out;
}
}
...
  我们让它循环,直到有可用数据,如果没有则使用wait_event_interruptible()(它是一个宏,不是函数,这就是为什么要通过值的方式给队列传递)来等待。好吧,如果wait_event_interruptible()被中断,它返回一个非0值,这个值代表-ERESTARTSYS。这段代码意味着系统调用应该重新启动。file->f_flags检查以非阻塞模式打开的文件数:如果没有数据,返回-EAGAIN。
  我们不能使用if()来替代while(),因为可能有许多进程正等待数据。当write方法唤醒它们时,调度程序以不可预知的方式选择一个来运行,因此,在这段代码有机会执行的时候,缓冲区可能再次空出。现在,我们需要将数据从buf->data 复制到用户空间。copy_to_user()内核函数就干了此事:
  size = min(size, (size_t) (buf->end - buf->read_ptr));
  if (copy_to_user(out, buf->read_ptr, size)) {
  result = -EFAULT;
  goto out;
  }
  如果用户空间指针错误,那么调用可能会失败;如果发生了此事,我们就返回-EFAULT。记住,不要相信任何来自内核外的事物!
  buf->read_ptr += size;
  result = size;
  out:
  return result;
  }
  为了使数据在任意块可读,需要进行简单运算。该方法返回读入的字节数,或者一个错误代码。
  写方法更简短。首先,我们检查缓冲区是否有足够的空间,然后我们使用copy_from_userspace()函数来获取数据。再然后read_ptr和结束指针会被重置,并且反转存储缓冲区内容:
  buf->end = buf->data + size;
  buf->read_ptr = buf->data;
  if (buf->end > buf->data)
  reverse_phrase(buf->data, buf->end - 1);
  这里, reverse_phrase()干了所有吃力的工作。它依赖于reverse_word()函数,该函数相当简短并且标记为内联。这是另外一个常见的优化;但是,你不能过度使用。因为过多的内联会导致内核映像徒然增大。
  最后,我们需要唤醒read_queue中等待数据的进程,就跟先前讲过的那样。wake_up_interruptible()就是用来干此事的:
  wake_up_interruptible(&buf->read_queue);
  耶!你现在已经有了一个内核模块,它至少已经编译成功了。现在,是时候来测试了。
  调试内核代码
  或许,内核中最常见的调试方法就是打印。如果你愿意,你可以使用普通的printk() (假定使用KERN_DEBUG日志等级)。然而,那儿还有更好的办法。如果你正在写一个设备驱动,这个设备驱动有它自己的“struct device”,可以使用pr_debug()或者dev_dbg():它们支持动态调试(dyndbg)特性,并可以根据需要启用或者禁用(请查阅Documentation/dynamic-debug-howto.txt)。对于单纯的开发消息,使用pr_devel(),除非设置了DEBUG,否则什么都不会做。要为我们的模块启用DEBUG,请添加以下行到Makefile中:
  CFLAGS_reverse.o := -DDEBUG
  完了之后,使用dmesg来查看pr_debug()或pr_devel()生成的调试信息。 或者,你可以直接发送调试信息到控制台。要想这么干,你可以设置console_loglevel内核变量为8或者更大的值(echo 8 /proc/sys/kernel/printk),或者在高日志等级,如KERN_ERR,来临时打印要查询的调试信息。很自然,在发布代码前,你应该移除这样的调试声明。
  注意内核消息出现在控制台,不要在Xterm这样的终端模拟器窗口中去查看;这也是在内核开发时,建议你不在X环境下进行的原因。
  惊喜,惊喜!
  编译模块,然后加载进内核:
  $ make
  $ sudo insmod reverse.ko buffer_size=2048
  $ lsmod
  reverse 2419 0
  $ ls -l /dev/reverse
  crw-rw-rw- 1 root root 10, 58 Feb 22 15:53 /dev/reverse
  一切似乎就位。现在,要测试模块是否正常工作,我们将写一段小程序来翻转它的第一个命令行参数。main()(再三检查错误)可能看上去像这样:
  int fd = open("/dev/reverse", O_RDWR);
  write(fd, argv[1], strlen(argv[1]));
  read(fd, argv[1], strlen(argv[1]));
  printf("Read: %s\n", argv[1]);
  像这样运行:
  $ ./test 'A quick brown fox jumped over the lazy dog'
  Read: dog lazy the over jumped fox brown quick A
  它工作正常!玩得更逗一点:试试传递单个单词或者单个字母的短语,空的字符串或者是非英语字符串(如果你有这样的键盘布局设置),以及其它任何东西。
  现在,让我们让事情变得更好玩一点。我们将创建两个进程,它们共享一个文件描述符(及其内核缓冲区)。其中一个会持续写入字符串到设备,而另一个将读取这些字符串。在下例中,我们使用了fork(2)系统调用,而pthreads也很好用。我也省略打开和关闭设备的代码,并在此检查代码错误(又来了):
  char *phrase = "A quick brown fox jumped over the lazy dog";
  if (fork())
  /* Parent is the writer */
  while (1)
  write(fd, phrase, len);
  else
  /* child is the reader */
  while (1) {
  read(fd, buf, len);
  printf("Read: %s\n", buf);
  }
  你希望这个程序会输出什么呢?下面就是在我的笔记本上得到的东西:
  Read: dog lazy the over jumped fox brown quick A
  Read: A kcicq brown fox jumped over the lazy dog
  Read: A kciuq nworb xor jumped fox brown quick A
  Read: A kciuq nworb xor jumped fox brown quick A
  ...
  这里发生了什么呢?就像举行了一场比赛。我们认为read和write是原子操作,或者从头到尾一次执行一个指令。然而,内核确实无序并发的,随便就重新调度了reverse_phrase()函数内部某个地方运行着的写入操作的内核部分。如果在写入操作结束前就调度了read()操作呢?就会产生数据不完整的状态。这样的bug非常难以找到。但是,怎样来处理这个问题呢?
  基本上,我们需要确保在写方法返回前没有read方法能被执行。如果你曾经编写过一个多线程的应用程序,你可能见过同步原语(锁),如互斥锁或者信号。Linux也有这些,但有些细微的差别。内核代码可以运行进程上下文(用户空间代码的“代表”工作,就像我们使用的方法)和终端上下文(例如,一个IRQ处理线程)。如果你已经在进程上下文中和并且你已经得到了所需的锁,你只需要简单地睡眠和重试直到成功为止。在中断上下文时你不能处于休眠状态,因此代码会在一个循环中运行直到锁可用。关联原语被称为自旋锁,但在我们的环境中,一个简单的互斥锁 —— 在特定时间内只有唯一一个进程能“占有”的对象 —— 就足够了。处于性能方面的考虑,现实的代码可能也会使用读-写信号。
  锁总是保护某些数据(在我们的环境中,是一个“struct buffer”实例),而且也常常会把它们嵌入到它们所保护的结构体中。因此,我们添加一个互斥锁(‘struct mutex lock’)到“struct buffer”中。我们也必须用mutex_init()来初始化互斥锁;buffer_alloc是用来处理这件事的好地方。使用互斥锁的代码也必须包含linux/mutex.h。
  互斥锁很像交通信号灯 —— 要是司机不看它和不听它的,它就没什么用。因此,在对缓冲区做操作并在操作完成时释放它之前,我们需要更新reverse_read()和reverse_write()来获取互斥锁。让我们来看看read方法 —— write的工作原理相同:
  static ssize_t reverse_read(struct file *file, char __user * out,
  size_t size, loff_t * off)
  {
  struct buffer *buf = file->private_data;
  ssize_t result;
  if (mutex_lock_interruptible(&buf->lock)) {
  result = -ERESTARTSYS;
  goto out;
  }
  我们在函数一开始就获取锁。mutex_lock_interruptible()要么得到互斥锁然后返回,要么让进程睡眠,直到有可用的互斥锁。就像前面一样,_interruptible后缀意味着睡眠可以由信号来中断。
  while (buf->read_ptr == buf->end) {
  mutex_unlock(&buf->lock);
  /* ... wait_event_interruptible() here ... */
  if (mutex_lock_interruptible(&buf->lock)) {
  result = -ERESTARTSYS;
  goto out;
  }
  }
  下面是我们的“等待数据”循环。当获取互斥锁时,或者发生称之为“死锁”的情境时,不应该让进程睡眠。因此,如果没有数据,我们释放互斥锁并调用wait_event_interruptible()。当它返回时,我们重新获取互斥锁并像往常一样继续:
  if (copy_to_user(out, buf->read_ptr, size)) {
  result = -EFAULT;
  goto out_unlock;
  }
  ...
  out_unlock:
  mutex_unlock(&buf->lock);
  out:
  return result;
  最后,当函数结束,或者在互斥锁被获取过程中发生错误时,互斥锁被解锁。重新编译模块(别忘了重新加载),然后再次进行测试。现在你应该没发现毁坏的数据了。
  接下来是什么?
  现在你已经尝试了一次内核黑客。我们刚刚为你揭开了这个话题的外衣,里面还有更多东西供你探索。我们的第一个模块有意识地写得简单一点,在从中学到的概念在更复杂的环境中也一样。并发、方法表、注册回调函数、使进程睡眠以及唤醒进程,这些都是内核黑客们耳熟能详的东西,而现在你已经看过了它们的运作。或许某天,你的内核代码也将被加入到主线Linux源代码树中 —— 如果真这样,请联系我们!

posted @ 2014-10-08 09:23 顺其自然EVO 阅读(199) | 评论 (0)编辑 收藏

优化临时表使用,SQL语句性能提升100倍

【问题现象】
  线上mysql数据库爆出一个慢查询,DBA观察发现,查询时服务器IO飙升,IO占用率达到100%, 执行时间长达7s左右。
  SQL语句如下:
  SELECT DISTINCT g.*, cp.name AS cp_name, c.name AS category_name, t.name AS type_name FROMgm_game g LEFT JOIN gm_cp cp ON cp.id = g.cp_id AND cp.deleted = 0 LEFT JOIN gm_category c ON c.id = g.category_id AND c.deleted = 0 LEFT JOIN gm_type t ON t.id = g.type_id AND t.deleted = 0 WHERE g.deleted = 0 ORDER BY g.modify_time DESC LIMIT 20 ;
  【问题分析】
  使用explain查看执行计划,结果如下:
  这条sql语句的问题其实还是比较明显的:
  查询了大量数据(包括数据条数、以及g.* ),然后使用临时表order by,但最终又只返回了20条数据。
  DBA观察到的IO高,是因为sql语句生成了一个巨大的临时表,内存放不下,于是全部拷贝到磁盘,导致IO飙升。
  【优化方案】
  优化的总体思路是拆分sql,将排序操作和查询所有信息的操作分开。
  第一条语句:查询符合条件的数据,只需要查询g.id即可
  SELECT DISTINCT g.id FROM gm_game g LEFT JOIN gm_cp cp ON cp.id = g.cp_id AND cp.deleted = 0 LEFT JOIN gm_category c ON c.id = g.category_id AND c.deleted = 0 LEFT JOIN gm_type t ON t.id = g.type_id AND t.deleted = 0 WHERE g.deleted = 0 ORDER BY g.modify_time DESC LIMIT 20 ;
  第二条语句:查询符合条件的详细数据,将第一条sql的结果使用in操作拼接到第二条的sql
  SELECT DISTINCT g.*, cp.name AS cp_name,c.name AS category_name,t.name AS type_name FROMgm_game g LEFT JOIN gm_cp cp ON cp.id = g.cp_id AND cp.deleted = 0 LEFT JOIN gm_category c ON c.id = g.category_id AND c.deleted = 0 LEFT JOIN gm_type t ON t.id = g.type_id AND t.deleted = 0 WHERE g.deleted = 0 and g.id in(…………………) ORDER BY g.modify_time DESC ;
  【实测效果】
  在SATA机器上测试,优化前大约需要50s,优化后第一条0.3s,第二条0.1s,优化后执行速度是原来的100倍以上,IO从100%降到不到1%
  在SSD机器上测试,优化前大约需要7s,优化后第一条0.3s,第二条0.1s,优化后执行速度是原来的10倍以上,IO从100%降到不到1%
  可以看出,优化前磁盘io是性能瓶颈,SSD的速度要比SATA明显要快,优化后磁盘不再是瓶颈,SSD和SATA性能没有差别。
  【理论分析】
  MySQL在执行SQL查询时可能会用到临时表,一般情况下,用到临时表就意味着性能较低。
  临时表存储
  MySQL临时表分为“内存临时表”和“磁盘临时表”,其中内存临时表使用MySQL的MEMORY存储引擎,磁盘临时表使用MySQL的MyISAM存储引擎;
  一般情况下,MySQL会先创建内存临时表,但内存临时表超过配置指定的值后,MySQL会将内存临时表导出到磁盘临时表;
  Linux平台上缺省是/tmp目录,/tmp目录小的系统要注意啦。
  使用临时表的场景
  1)ORDER BY子句和GROUP BY子句不同, 例如:ORDERY BY price GROUP BY name;
  2)在JOIN查询中,ORDER BY或者GROUP BY使用了不是第一个表的列 例如:SELECT * from TableA, TableB ORDER BY TableA.price GROUP by TableB.name
  3)ORDER BY中使用了DISTINCT关键字 ORDERY BY DISTINCT(price)
  4)SELECT语句中指定了SQL_SMALL_RESULT关键字 SQL_SMALL_RESULT的意思就是告诉MySQL,结果会很小,请直接使用内存临时表,不需要使用索引排序 SQL_SMALL_RESULT必须和GROUP BY、DISTINCT或DISTINCTROW一起使用 一般情况下,我们没有必要使用这个选项,让MySQL服务器选择即可。
直接使用磁盘临时表的场景
  1)表包含TEXT或者BLOB列;
  2)GROUP BY 或者 DISTINCT 子句中包含长度大于512字节的列;
  3)使用UNION或者UNION ALL时,SELECT子句中包含大于512字节的列;
  临时表相关配置
  tmp_table_size:指定系统创建的内存临时表最大大小;
  http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_tmp_table_size
  max_heap_table_size: 指定用户创建的内存表的最大大小;
  http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_max_heap_table_size
  注意:最终的系统创建的内存临时表大小是取上述两个配置值的最小值。
  表的设计原则
  使用临时表一般都意味着性能比较低,特别是使用磁盘临时表,性能更慢,因此我们在实际应用中应该尽量避免临时表的使用。 常见的避免临时表的方法有:
  1)创建索引:在ORDER BY或者GROUP BY的列上创建索引;
  2)分拆很长的列:一般情况下,TEXT、BLOB,大于512字节的字符串,基本上都是为了显示信息,而不会用于查询条件, 因此表设计的时候,应该将这些列独立到另外一张表。
  SQL优化
  如果表的设计已经确定,修改比较困难,那么也可以通过优化SQL语句来减少临时表的大小,以提升SQL执行效率。
  常见的优化SQL语句方法如下:
  1)拆分SQL语句
  临时表主要是用于排序和分组,很多业务都是要求排序后再取出详细的分页数据,这种情况下可以将排序和取出详细数据拆分成不同的SQL,以降低排序或分组时临时表的大小,提升排序和分组的效率,我们的案例就是采用这种方法。
  2)优化业务,去掉排序分组等操作
  有时候业务其实并不需要排序或分组,仅仅是为了好看或者阅读方便而进行了排序,例如数据导出、数据查询等操作,这种情况下去掉排序和分组对业务也没有多大影响。
  如何判断使用了临时表?
  使用explain查看执行计划,Extra列看到Using temporary就意味着使用了临时表。

posted @ 2014-10-08 09:17 顺其自然EVO 阅读(220) | 评论 (0)编辑 收藏

浅谈关于java程序员面试的一些事项

本篇博文针对的是应届毕业生以及工作两三年左右的java程序员。
  为什么要跳槽?
  这是一个很广义的问题,每个人心中都有一份答案。
  例如:
  公司的待遇不好,
  薪资涨幅不符合预期要求,
  厌倦了出差的荒无天日的繁重工作,
  公司的妹子太少,
  领导太傲娇,
  同事之间关系太逼格,
  某某同学跳槽到某某公司之后涨到了多少多少钱,
  某某同学的朋友的同事的三姑妈家的大儿子的好基友在某某高就,
  等等辞职理由。
  咱们就不多说了,还是谈谈怎么应付面试吧。
  以下内容是我在面试中总结的一些经验,希望这些可以给各位带来帮助和启迪。
  简单的说一下笔试,笔试这个环节是很容易通过的,无非就是几张试卷,一共也就十几道题。一般由5至10个选择题+2至5个论述题+1至2个编程题 组成。
  接过笔试题之后,第一步要平静心态,第二步要浏览所有题目,第三步自然就是答题了~
  答题的时候,要先把自己会的快速的答上来,选择题自然不多说了,论述题根据自己的理解大致说明一下,多少会给你自己加分的。
  编程题其实也不难,出现几率最大的是写一个关于某某设计模式的例子,而设计模式的编码例子,出现最多的是单例模式、工厂模式和代理模式。
  有时候也会有一些算法的编码,一般是排序算法的编码实现。
  还有的笔试题,会有一些程序题,就是看程序,然后自己写出运行结果,这样的问题考察的是对java基础知识的掌握,所以,有坚固的基础是很重要滴!
  OK,笔试结束之后,下一个环节就是面试了,java程序员的一些面试问题主要有哪些呢?
  我个人认为主要有三方面:
  1. 关于java有关的技术问题
  2. 关于项目经验的问题
  3. 关于个人对团队的看法以及个人的职业规划
  咱们就一条一条来看,大家看完之后找相关资料然后一条一条的应对
  一、技术问题
  Struts1原理和Struts2原理以及区别和联系,在什么项目中用过,有什么体会。
  spring的原理  aop和ioc机制,如何使用,在哪个项目用到过?有什么体会。
  简要说明一下StrutsMVC和SpringMVC。
  servlet的原理,生命周期。
  socket 原理以及使用方式
  Linux常用命令,shell编程介绍
  java常用算法
  多线程、线程池、线程锁等等
  二叉树、java数据结构
  数据库mysql、Oracle的优缺点以及使用方法和sql语句,问的多的是如果模拟分页查询和多表查询
  Java垃圾回收机制
  敏捷开发的简要说明,是否了解
  OOA/OOD/OOP 的含义
  java加密与解密
  java网络通信、http协议要素
  是否熟悉设计模式?简要说一下自己所了解或者使用过的开发模式有哪些,在哪些场景中使用。

posted @ 2014-10-08 09:16 顺其自然EVO 阅读(187) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 36 37 38 39 40 41 42 43 44 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜